Ответ 1
Оба, получающие доступ к свойству, не определенному для объекта, и свойству, содержащему примитивное значение undefined
, вернут вам undefined
.
Например:
var obj = {
a: undefined
};
obj.a; // undefined
obj.b; // undefined
Разница в том, что a
является собственным свойством, а b
не является:
obj.hasOwnProperty('a'); // true
obj.hasOwnProperty('b'); // false
В первом случае a
является собственным свойством, даже если оно содержит undefined
как его значение. Во втором случае b
не является собственным свойством, доступ к obj.b
будет искать свойство с именем b
, все в цепочке прототипов.
Когда цепочка прототипов заканчивается (когда она достигает объекта с null
[[Prototype]]
), поиск свойств заканчивается и undefined
явно возвращается.
Вы должны знать, что метод hasOwnProperty
проверяет только, если свойство физически существует на объекте (собственные свойства), но мы также имеем унаследованные свойства, в этом случае мы можем использовать оператор in
, например:
function Test () {}
Test.prototype.a = 'foo'; // instances of Test will inherit from Test.prototype
var obj = new Test(); // { a="foo", b="bar"}
obj.b = 'bar';
obj.hasOwnProperty('a'); // false
'a' in obj; // true
obj.a; // 'foo'
obj.hasOwnProperty('b'); // true
Как вы можете видеть, obj
наследует от Test.prototype
, а свойство a
не является собственным свойством, но доступно через цепочку прототипов. Поэтому hasOwnProperty
возвращает false
, а оператор in
возвращает true
.
Вы можете видеть, как внутренние свойства решаются с помощью [[Get]]
внутренней операции
Примечания:
- Доступ к
undefined
в качестве идентификатора не считается безопасным в ECMAScript 3 (наиболее распространенной версии стандартного языка), поскольку вместо ключевого слова языка (например,null
) это просто свойство глобального объекта, и оно доступно для записи в этой версии Spec., что означает, что если кто-то заменит его значение (например,window.undefined = 'LOL';
), он сломает ваш код.
Оператор typeof
, поскольку вместо него могут использоваться ссылки @strager, например:
if (typeof obj.prop == 'undefined') { /*....*/ }
Этот оператор всегда возвращает строку (безопасно использовать ==
:), и ее значение зависит от типа его операнда, возможные значения описываются .
Другим распространенным способом решения этой проблемы является объявление вашей собственной переменной undefined
, доступной в области ваших функций, например, некоторые библиотеки используют следующий шаблон:
(function(undefined) {
// code here
})();
У функции есть аргумент с именем undefined
, и он выполняется немедленно, не передавая ему какое-либо значение (последняя пара или параны делают вызов).
Возможно, стоит упомянуть, что глобальное свойство undefined
было, наконец, описано в ECMAScript 5 как незаписываемое (неизменяемое, перечислимый и неконфигурируемый - не удаляемый -).
-
Использование метода
hasOwnProperty
непосредственно из экземпляра объекта также не считается безопасным, потому что, если у какого-либо объекта есть свойство с тем же именем, оригинальный метод будет затенен. Например:var obj = { hasOwnProperty: function () { /* evil code :) */ } };
Если вы вызываете:
obj.hasOwnProperty('prop');
Метод, определенный на объекте, будет выполнен (и вы не захотите этого, так как вы точно знаете, какой метод вы хотите вызывать...), потому что он сглаживает одно из Object.prototype
, однако это может быть безопасно вызывается:
Object.prototype.hasOwnProperty.call(obj, 'prop');