Выполняют ли следующие два оператора один и тот же вывод? Есть ли причина предпочесть один путь другому?
if (key in object)
if (object.hasOwnProperty(key))
Выполняют ли следующие два оператора один и тот же вывод? Есть ли причина предпочесть один путь другому?
if (key in object)
if (object.hasOwnProperty(key))
Будьте осторожны - они не будут давать тот же результат.
in
также вернет true
, если key
будет найден где-то в цепочке прототипов, тогда как Object.hasOwnProperty
(как уже говорит нам имя) вернет только true
, если key
доступно в этот объект напрямую (его "владеет" свойством).
Я попытаюсь объяснить другим примером. Скажем, у нас есть следующий объект с двумя свойствами:
function TestObj(){
this.name = 'Dragon';
}
TestObj.prototype.gender = 'male';
Позвольте создать экземпляр TestObj:
var o = new TestObj();
Давайте рассмотрим экземпляр объекта:
console.log(o.hasOwnProperty('name')); // true
console.log('name' in o); // true
console.log(o.hasOwnProperty('gender')); // false
console.log('gender' in o); // true
Вывод:
в operator возвращает true всегда, если свойство доступно объекту, непосредственно или из прототипа
hasOwnProperty() возвращает true, только если свойство присутствует в экземпляре, но не на его прототипе
Если мы хотим проверить, что какое-то свойство существует на прототипе, логически, мы бы сказали:
console.log(('name' in o) && !o.hasOwnProperty('name')); //false
console.log(('gender' in o) && !o.hasOwnProperty('gender')); //true - it in prototype
Наконец:
Итак, что касается утверждения, что эти два условия...
if (key in object)
if (object.hasOwnProperty(key))
... производят одинаковый результат, ответ очевиден, это зависит.
in
также проверит наличие унаследованных свойств, что не относится к hasOwnProperty
.
Таким образом, hasOwnProperty() не выглядит в прототипе, а в нем - в прототипе.
Записанная форма O'Reilly High Performance Javascript:
Вы можете определить, имеет ли объект член экземпляра с имя с помощью метода hasOwnProperty() и передачи в имя участника. Чтобы определить, имеет ли объект доступ к свойство с заданным именем, вы можете использовать оператор in. Например:
var book = {
title: "High Performance JavaScript",
publisher: "Yahoo! Press"
};
alert(book.hasOwnProperty("title")); //true
alert(book.hasOwnProperty("toString")); //false
alert("title" in book); //true
alert("toString" in book); //true
В этом коде hasOwnProperty() возвращает true, когда "title" передается в потому что заголовок является экземпляром объекта; метод возвращает false, когда "toString" передается, потому что он не существует в экземпляре. когда каждое имя свойства используется с оператором in, результат верен оба раза, потому что он ищет экземпляр и прототип.
В другой форме (вызываемой для) перечисляются имена свойств (или ключи) объекта. На каждой итерации другая строка имени свойства из объект присваивается переменной. Обычно необходимо протестировать object.hasOwnProperty(переменная), чтобы определить, будет ли имя свойства действительно является членом объекта или был найден вместо этого в цепочке прототипов.
for (myvar in obj) {
if (obj.hasOwnProperty(myvar)) { ... } }
(от Крокфорда Javascript: хорошие части)
У тебя есть очень хорошие ответы. Я просто хочу предложить что-то, что избавит вас от необходимости проверять "hasOwnProperty" при повторении объекта.
При создании объекта обычно люди будут создавать его таким образом:
const someMap = {}
// equivalent to: Object.create(Object.prototype)
// someMap.constructor will yield -> function Object() { [native code] }
Теперь, если вы хотите выполнить итерацию через "someMap", вам придется сделать это следующим образом:
const key
for(key in someMap ){
if (someMap.hasOwnProperty(key)) {
// Do something
}
}
Мы делаем это, чтобы избежать итерации над унаследованными свойствами.
Если вы намереваетесь создать простой объект, который будет использоваться только как "карта" (т.е. пары ключ-значение), вы можете сделать это следующим образом:
const newMap = Object.create(null);
// Now, newMap won't have prototype at all.
// newMap.constructor will yield -> undefined
Итак, теперь будет безопасно повторять так:
for(key in cleanMap){
console.log(key + " -> " + newMap [key]);
// No need to add extra checks, as the object will always be clean
}
Я узнал этот удивительный совет здесь
Первая версия короче (особенно в сокращенном коде, где переменные переименованы)
a in b
vs
b.hasOwnProperty(a)
В любом случае, как сказал @AndreMeinhold, они не всегда дают одинаковый результат.