Подтвердить что ты не робот

Зачем использовать 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 может использоваться для объектов, которые не имеют этого метода?

4b9b3361

Ответ 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.