Почему не все можно назначить в JavaScript?
Я был воспитан с "все в JavaScript объектно-ориентированной и назначаемой" парадигме. Поэтому я прожил свою счастливую жизнь, пока...
var x = {};
x.field = true;
x.field.netType = "System.Boolean";
alert(x.field.netType);
Он компилируется, но предупреждение продолжает давать met undefined. Почему!?
Ответы
Ответ 1
Примитивы (строки, числа, true
и false
) в JavaScript - это объекты не. Однако, когда они используются с .
или []
, как если бы они были объектами, язык обязывает, неявно создавая для них обертки объектов.
В вашем примере это произошло. Назначение свойства объекта действительно работало, поэтому ошибки не было, но этот объект-оболочка был немедленно выброшен.
С другой стороны:
var x = {};
x.field = new Boolean(true);
x.field.netType = "System.Boolean";
alert(x.field.netType);
(Я бы не советовал это делать, используя объекты, созданные из примитивных типов оберток, имеет тенденцию иметь странные эффекты, поскольку эти значения распространяются на код, который их не ожидает.)
Ответ 2
x.field = true;
x.field.netType = "System.Boolean";
фактически работает.
x.field
, который является примитивным булевым значением, преобразуется в объект внутри, но у нас нет ссылки на него, поэтому он становится мусором. Если мы сохраним refrence x.field
, чтобы он не был мусором, мы можем получить значение. как это....
x.field = true;
var y = x.field.netType = "System.Boolean";
alert(y);
Если вы напишете код вроде этого
var x = {};
x.field = {};
x.field.netType = "System.Boolean";
alert(x.field.netType);
Тогда он будет работать.
В вашем коде эта строка x.field.netType = "System.Boolean";
будет вызывать ошибку в `strict mode
`//Cannot assign to read only property 'netType' of true`
Почему эта строка x.field.netType
дает undefined
Объекты этого типа являются просто обертками, их значение является примитивом, которое они обертывают, и они обычно прибегают к этому значению по мере необходимости.
JavaScript будет легко принуждать между primitives and objects
.
var a = 'Intekhab';
a.length;//In this case the string value is coerced to a string object in order to access the property length.
var Twelve = new Number(12);
var fifteen = Twelve + 3; // In this case Object Twelve is coerced to a primitive value.
fifteen; //15
Если JavaScript обнаруживает попытку присвоить свойство примитиву, он действительно принудит примитив к объекту. Этот новый объект не имеет ссылок и сразу станет кормом для сбора мусора.
var primitive = "september";
primitive.vowels = 3;
//new object created to set property
(new String("september")).vowels = 3;
primitive.vowels;
//another new object created to retrieve property
(new String("september")).vowels; //undefined
Ответ 3
x.field
- это булево значение; Булевские значения являются примитивами и доступны только для чтения. Когда вы пытаетесь присвоить значение x.field.netType
, вы пытаетесь изменить значение x.field
. Пояснительный ответ в основном объясняет это.
В режиме "нормального" JavaScript это означает, что значение просто undefined
.
Причина почему кто-то в комментариях предлагает строгий режим (который вы обязательно должны использовать) заключается в том, что строгий режим выдаст ошибку, сообщающую вам, что вы пытаетесь присвоить значение read- только значение и не позволяйте вам делать это, вместо того, чтобы молча возвращать undefined
всякий раз, когда вы обращаетесь к этому свойству.
'use strict';
var foo = true;
foo.bar = 'qux'; // this line will throw an Error
В соответствии с примером Pointy он действительно делает ошибку, по крайней мере, на Node 4.0. Я понятия не имею, что использует JS-движок Pointy, но он работает неправильно.
> (function() { 'use strict'; (true).x = 0; })()
TypeError: Cannot assign to read only property 'x' of true
at repl:1:38
at repl:1:45
at REPLServer.defaultEval (repl.js:154:27)
at bound (domain.js:254:14)
at REPLServer.runBound [as eval] (domain.js:267:12)
at REPLServer.<anonymous> (repl.js:308:12)
at emitOne (events.js:77:13)
at REPLServer.emit (events.js:169:7)
at REPLServer.Interface._onLine (readline.js:209:10)
at REPLServer.Interface._line (readline.js:548:8)