Зачем использовать Object.prototype.hasOwnProperty.call(myObj, prop) вместо myObj.hasOwnProperty(prop)?
Если я правильно понимаю, каждый объект в Javascript наследуется от прототипа Object, что означает, что каждый объект в Javascript имеет доступ к функции hasOwnProperty через цепочку прототипов.
При чтении исходного кода require.js я наткнулся на эту функцию:
function hasProp(obj, prop) {
return hasOwn.call(obj, prop);
}
hasOwn
является ссылкой на Object.prototype.hasOwnProperty
. Существует ли какая-либо практическая разница в написании этой функции как
function hasProp(obj, prop) {
return obj.hasOwnProperty(prop);
}
И так как мы на нем, почему мы вообще определяем эту функцию? Является ли это просто вопросом ярлыков и локального кэширования доступа к свойствам для (незначительного) прироста производительности, или я пропускаю любые случаи, когда hasOwnProperty может использоваться для объектов, которые не имеют этого метода?
Ответы
Ответ 1
Есть ли какая-либо практическая разница между моими примерами?
Пользователь может иметь объект JavaScript, созданный с помощью Object.create(null)
, который будет иметь цепочку null
[[Prototype]]
, и поэтому на нем не будет hasOwnProperty()
. По этой причине использование вашей второй формы не сработает.
Это также более безопасная ссылка на Object.prototype.hasOwnProperty()
(а также более короткая).
Вы можете себе представить, что кто-то мог сделать...
var someObject = {
hasOwnProperty: function(lol) {
return true;
}
};
Что бы сделать сбой hasProp(someObject)
, если бы он был реализован как ваш второй пример (он найдет этот метод непосредственно на объекте и вызовет это вместо делегирования Object.prototype.hasOwnProperty
).
Но это менее вероятно, что кто-то переопределит ссылку Object.prototype.hasOwnProperty
.
И так как мы на нем, почему мы вообще определяем эту функцию?
См. выше.
Это просто вопрос о ярлыках и локальном кэшировании доступа к (небольшой) прирост производительности...
Это может сделать его более быстрым в теории, так как цепочка [[Prototype]]
не обязательно должна выполняться, но я подозреваю, что это незначительно, а не причина, почему это реализация.
... или я пропускаю любые случаи, когда hasOwnProperty
может использоваться для объектов, которые не имеют этого метода?
hasOwnProperty()
существует на Object.prototype
, но может быть переопределен. Каждый собственный объект JavaScript (но хост-объекты не гарантируют этого, см. Подробное объяснение RobG) имеет Object.prototype
в качестве своего последнего объекта в цепочке до null
(за исключением, конечно, для объекта, возвращаемого Object.create(null)
).
Ответ 2
Если я правильно понимаю, каждый объект в Javascript наследуется от прототипа Object
Это может показаться расщеплением волосков, но существует разница между javascript (общий термин для реализации ECMAScript) и ECMAScript (язык, используемый для реализации javascript). ECMAScript определяет схему наследования, а не javascript, поэтому только собственные объекты ECMAScript должны реализовать эту схему наследования.
Запустимая javascript-программа состоит из по крайней мере встроенных объектов ECMAScript (Object, Function, Number и т.д.) и, возможно, некоторых собственных объектов (например, функций). Он также может содержать некоторые объекты хоста (такие как объекты DOM в браузере или другие объекты в других средах хоста).
В то время как встроенные и собственные объекты должны реализовывать схему наследования, определенную в ECMA-262, объекты-хозяева этого не делают. Поэтому не все объекты в среде javascript должны наследоваться от Object.prototype. Например, объекты хоста в IE, реализованные как объекты ActiveX, будут вызывать ошибки, если их обрабатывают как родные объекты (поэтому почему try..catch используется для инициализации объектов MS XMLHttpRequest). Некоторые объекты DOM (например, NodeLists в IE в режиме quirks), если они переданы методам Array, будут вызывать ошибки, объекты DOM в IE 8 и ниже не имеют ECMAScript-подобной схемы наследования и т.д.
Поэтому не следует предполагать, что все объекты в среде javascript наследуются от Object.prototype.
что означает, что каждый объект в Javascript имеет доступ к функции hasOwnProperty через цепочку прототипов
Это не верно для некоторых объектов хоста в IE в режиме quirks (и IE 8 и ниже всегда).
Учитывая вышеизложенное, стоит подумать, почему у объекта может быть свой собственный метод hasOwnProperty и целесообразность вызова другого метода hasOwnProperty вместо первого тестирования, если это хорошая идея или нет.
Изменить
Я подозреваю, что причина использования Object.prototype.hasOwnProperty.call
заключается в том, что в некоторых браузерах объекты хоста не имеют метода hasOwnProperty, альтернативным может быть использование вызова, а встроенный метод. Однако делать это в целом не представляется хорошей идеей по причинам, указанным выше.
В случае объектов хоста оператор in может использоваться для проверки свойств в целом, например.
var o = document.getElementsByTagName('foo');
// false in most browsers, throws an error in IE 6, and probably 7 and 8
o.hasOwnProperty('bar');
// false in all browsers
('bar' in o);
// false (in all browsers? Do some throw errors?)
Object.prototype.hasOwnProperty.call(o, 'bar');
Альтернатива (проверена в IE6 и других):
function ownProp(o, prop) {
if ('hasOwnProperty' in o) {
return o.hasOwnProperty(prop);
} else {
return Object.prototype.hasOwnProperty.call(o, prop);
}
}
Таким образом вы только специально вызываете встроенный hasOwnProperty, где объект не имеет его (унаследованного или иным образом).
Однако, если объект не имеет метода hasOwnProperty
, он, вероятно, так же подходит для использования оператора in, поскольку у объекта, вероятно, нет схемы наследования, и все свойства находятся на объекте (это просто предположение, хотя), например оператор in является обычным (и, казалось бы, успешным) способом тестирования поддержки объектов DOM для свойств.
Ответ 3
JavaScript не защищает имя свойства hasOwnProperty
Если существует вероятность того, что объект может иметь свойство с этим именем, для получения правильных результатов необходимо использовать внешний hasOwnProperty:
Вы можете скопировать вложенные ниже фрагменты кода на консоль браузеров, чтобы лучше понять
var foo = {
hasOwnProperty: function() {
return false;
},
bar: 'I belong to foo'
};
Всегда возвращает false
foo.hasOwnProperty('bar'); // false
Используйте другой объект hasOwnProperty и вызовите его с этим, установленным в foo
({}).hasOwnProperty.call(foo, 'bar'); // true
Для этого также возможно использовать свойство hasOwnProperty из прототипа Object
Object.prototype.hasOwnProperty.call(foo, 'bar'); // true
Ответ 4
Информация, содержащаяся в обоих существующих ответах, находится на месте. Однако использование:
('propertyName' in obj)
упоминается несколько раз. Следует отметить, что реализация hasOwnProperty
вернет true, только если свойство непосредственно содержится в тестируемом объекте.
Оператор in
также проверяет цепочку прототипов.
Это означает, что свойства экземпляра вернут true при передаче в hasOwnProperty
, когда свойства прототипа вернут false.
Используя оператор in
, свойства экземпляра и прототипа вернут true.