最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How does the Array.prototype.includes function compare objects - Stack Overflow

programmeradmin2浏览0评论

In ECMA Specs we read that Array.prototype.includes uses SameValueZero algorithm when paring if an array includes given element. This algorithm, when the element is an Object, it uses SameValueNonNumeric algorithm which basically checks if types of pared 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 parison 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 parison is not so straightforward in JS.

In ECMA Specs we read that Array.prototype.includes uses SameValueZero algorithm when paring if an array includes given element. This algorithm, when the element is an Object, it uses SameValueNonNumeric algorithm which basically checks if types of pared 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 parison 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 parison is not so straightforward in JS.

Share Improve this question asked Apr 14, 2020 at 8:53 mtxmtx 1,2442 gold badges20 silver badges43 bronze badges 4
  • It's basically a === b - are they literally the same object or not. – VLAZ Commented Apr 14, 2020 at 9:00
  • 1 Its nontrivial for every case. How do you pare to objects in general? If 2 objects point to the same instance or when they have the same properties? There is no general answer. So the better question should by WHY do you need that? I feel like paring objects always indicates a bad approach. Just my personal opinion. – Aaron Commented Apr 14, 2020 at 9:01
  • 1 @Aaron thanks for the ment, I think you nailed it. I wanted to use this function to establish whether in the list of documents (objects) there is already an object with same contents. Seems that it was bad approach, finding object by some unique id will work better. Initially I thought 'includes' will make such 'deep' property-by-property parison. – mtx Commented Apr 14, 2020 at 9:48
  • Sometimes you gotta hear somebody elses opinion to re-think your design. Glad it pointed you in the right direction :) – Aaron Commented Apr 14, 2020 at 10:27
Add a ment  | 

5 Answers 5

Reset to default 3

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

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 pare object contents in a meaningful manner.

It is very simple to pare objects the "regular" way though, i.e. pare 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

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.

Objects and symbols are pared 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));

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

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

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

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

])

发布评论

评论列表(0)

  1. 暂无评论