mtx
mtx

Reputation: 1234

How does the Array.prototype.includes function compare objects

In ECMA Specs we read that Array.prototype.includes uses SameValueZero algorithm when comparing if an array includes given element. This algorithm, when the element is an Object, it uses SameValueNonNumeric algorithm which basically checks if types of compared elements are matching and finally, in the last point of the algorithm it checks:

If x and y are the same Object value, return true. Otherwise, return false.

My question :

How does SameValueNonNumeric algorithm performs the object comparison step? How does it establish that "x and y are the same Object value"? I couldn't find this in specs.

From this and this question it seems that object comparison is not so straightforward in JS.

Upvotes: 4

Views: 6480

Answers (5)

fjc
fjc

Reputation: 5815

Array.prototype.includes effectively compares using the === operator. So objects are compared by references, primitives by value.

Here's an example comparing includes results to === results:

const object = {'a': 'b'};
const copyOfObject = JSON.parse(JSON.stringify(object));
const array = [object, 'a', 1];

console.table([
    {
        'comparison': 'object vs object',
        'result for Array.prototype.includes': array.includes(object),
        'result for === operator': object === array[0]
    },
    {
        'comparison': 'object vs copyOfObject',
        'result for Array.prototype.includes': array.includes(copyOfObject),
        'result for === operator': object === copyOfObject
    },
    {
        'comparison': 'string "a" vs string "a"',
        'result for Array.prototype.includes': array.includes('a'),
        'result for === operator': 'a' === array[1]
    },
    {
        'comparison': 'string "a" vs string "b"',
        'result for Array.prototype.includes': array.includes('b'),
        'result for === operator': 'b' === array[1]
    },
    {
        'comparison': 'number 1 vs number 1',
        'result for Array.prototype.includes': array.includes(1),
        'result for === operator': 1 === array[2]
    },
    {
        'comparison': 'number 1 vs number 2',
        'result for Array.prototype.includes': array.includes(2),
        'result for === operator': 2 === array[2]
    },

])

Upvotes: 0

customcommander
customcommander

Reputation: 18901

Objects and symbols are compared by reference.

We know that {} === {} or Symbol() === Symbol() both return false. Quick example:

console.log([{}].includes({}));
console.log([Symbol()].includes(Symbol()));

If they refer to the same "value" i.e. reference, then they'll be equal:

const obj = {};
const sym = Symbol();

console.log([obj].includes(obj));
console.log([sym].includes(sym));

Upvotes: 0

CherryDT
CherryDT

Reputation: 29012

They are "the same Object value" if they refer to the same block of memory, if you will.

The non-straightforward questions and answers you find are all about how to compare object contents in a meaningful manner.

It is very simple to compare objects the "regular" way though, i.e. compare the reference, and that's what includes does here too. I agree that the text in SameValueNonNumber is a bit unclear at that point, other algorithms specify that more clearly such as here at step 1f:

Return true if x and y refer to the same object. Otherwise, return false.

So:

const a = { hello: 'world' }
const b = a
const c = { hello: 'world' }

// Now, a and b refer to the same object, but a/b and c do not.

console.log([a].includes(a)) // true
console.log([a].includes(b)) // true
console.log([a].includes(c)) // false

Upvotes: 2

Shubham Khatri
Shubham Khatri

Reputation: 281686

Array.prototype.includes is not supposed to give you correct results for object check and is designed to work for Boolean, String and Number values

For an object it basically just does a reference check, so if the object contains same reference as the one in the array, it returns true else just will return false regardless of the values within the object

var arr = [{x: 1, y: 2}, {x: 2, y: 'as'}, {x: 'in', y: 'po'}];
console.log(arr.includes({x: 2, y: 'as'}));
console.log(arr.includes(arr[1]));

For object existence check you need to make use of Array.prototype.find and check for all values of object

Upvotes: 3

Radu Diță
Radu Diță

Reputation: 14171

I'm guessing it uses the The Abstract Equality Comparison Algorithm for determining if the object values are the same.

Specs for the algorithm here.

Upvotes: 0

Related Questions