var a = new Object;
var b = new Object;
var c = new Object;
c[a] = a;
c[b] = b;
console.log(c[a] === a);
Я проверил код выше и получаю false
. Если я попробую console.log(c[a] === b)
, тогда будет напечатан true
.
Почему?
var a = new Object;
var b = new Object;
var c = new Object;
c[a] = a;
c[b] = b;
console.log(c[a] === a);
Я проверил код выше и получаю false
. Если я попробую console.log(c[a] === b)
, тогда будет напечатан true
.
Почему?
Проблема здесь связана с тем, как установлены клавиши Object
. Из MDN:
Параметры
nameValuePair1, nameValuePair2,... nameValuePairN
- Пары имен (строк) и значений (любое значение), где имя отделяется от значения двоеточием.
Значение
- Любое значение.
Доступ к объектным значениям (через соответствующий ключ) осуществляется тремя способами:
var o = {};
var key = "fun";
// method 1:
o[key] = "the key will be equal to `key.toString()"
// method 2:
o.key = "the key will be equal to 'key'"
// method 3:
o["key2"] = "the key will be equal to `key2`"
/*
{
"fun" : "the key will be...", // method 1
"key" : "the key will be...", // method 2
"key2": "the key will be..." // method 3
}
*/
При использовании обозначения в виде кронштейна вам нужно учитывать разрыв... между скобками! Объекты устанавливают свои ключи и значения с помощью метода toString
, если только они не передают строку (тогда нет точки в toString
). При использовании точечной нотации они используют .key
в качестве ключа.
Посмотрите на ваш случай:
var a = {}
, b = {}
, c = {}
;
c[a] = a;
// `a` is not a string, and we're using brackets, so the key
// will be equal to `key.toString()`:
// a.toString() === "[object Object]"
// Try the following in your console: `{}.toString()`
// Note how this is different from console.log({}), since
// the console exposes your object (that why the dev console is useful)
// c is now: `{ "[object Object]" : a }`
c[b] = b;
// b is also an object, so `b.toString()` is the same as `a.toString()`
// that means c is now `{ "[object Object]" : b }`
assert c[a] === a
// a.toString() == b.toString() == "[object Object]"
// and we just noted that c was `{ "[object Object]" : b }`
// so of course this is false
assert c[b] === b
// true because c[b] == b;
assert c["[object Object]"] === b;
// also true
assert c.b === b
// false, since `c` has no "b" key (c.b is `undefined`)
Объект не является допустимым ключом для объекта JavaScript, только строки
Итак, когда вы это сделаете:
c[a] = a;
c[b] = b;
Компилятор не может использовать a или b как ключ для c, как в c [a] или c [b].
Однако это не подводит, потому что JavaScript может обойти эту проблему. Сначала выясняется, что
Таким образом, компилятор JavaScript вызовет toString() каждой из этих переменных. И по умолчанию Object.prototype.toString возвращает "[object Object]" -string, потому что реализация является реализацией по умолчанию, которая делает это, и это значение становится новым ключом
c["[object Object]"] = a;
c["[object Object]"] = b; // overrides the previous
Это не то, что вы хотели. Проблема в том, что toString будет по умолчанию возвращать всегда одно и то же значение, поэтому настройки всегда будут поступать на один и тот же ключ.
Чтобы продемонстрировать, что toString на самом деле является проблемой, вы действительно можете сделать ужасный чит, чтобы каждый объект возвращал уникальную строку
// don't do this!!!
(function() {
var id=1;
Object.prototype.toString = function() {
if(!this._id) this._id = id++;
return "Object"+this._id;
}
}());
После этого ключ c [a] будет c [ "Object1" ], а c [b] будет c [ "Object2" ] и т.д.... и c [a] == a и c [ b] == b работают так, как ожидалось, но в реальной жизни это не очень хорошее решение.
Допустимым способом решения этого может быть либо использование другого ключа, возможно, идентификатора, назначенного объекту типа c [a.id] = a, или для использования объекта карты ES6, где можно использовать любое значение, включая объекты. как ключ.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
Объект Map - это простая карта ключа/значения. Любое значение (оба объекта и примитивные значения) могут использоваться как ключ или значение.
Я экспериментировал с ним немного, и @royhowie может быть прав. Как вы можете видеть в этой реализации, я переключил порядок назначений, а затем c [a] == a дал истину.
var a = new Object;
var b = new Object;
var c = new Object;
//I switched the following lines of code
c[b]=b;
c[a]=a;
console.log(c[a]===a);
Выход: true