if (введите объект) или if (object.hasOwnProperty (ключ)

173

Следующие два утверждения дают одинаковый результат? Есть ли причина предпочитать один путь другому?

 if (key in object)

 if (object.hasOwnProperty(key))
Лорейн Бернард
источник

Ответы:

181

Будьте осторожны - они не дадут того же результата.

inбудет также возвращаться, trueесли keyбудет найден где-то в цепочке прототипов , тогда как Object.hasOwnProperty(как уже говорит нам имя), будет возвращаться, только trueесли keyон доступен для этого объекта напрямую (его «владеет» свойством).

Андре Майнхольд
источник
3
что вы имеете в виду именно для in will also return true if key gets found somewhere in the prototype chain. ты можешь написать пример? Спасибо.
Лорейн Бернард
44
@Lor: ({foo:"bar"}).hasOwnProperty("toString")против"toString" in ({foo:"bar"})
Я ненавижу Ленивых
68

Я попытаюсь объяснить другим примером. Скажем, у нас есть следующий объект с двумя свойствами:

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

Вывод:

  • Оператор in возвращает true всегда, если свойство доступно для объекта, напрямую или из прототипа

  • hasOwnProperty () возвращает true, только если свойство существует в экземпляре, но не в его прототипе

Если мы хотим проверить, существует ли какое-либо свойство в прототипе, логически, мы бы сказали:

console.log(('name' in o) && !o.hasOwnProperty('name')); //false
console.log(('gender' in o) && !o.hasOwnProperty('gender')); //true - it's in prototype

В заключение:

Итак, что касается утверждения, что эти два условия ...

if (key in object)
if (object.hasOwnProperty(key))

... дать тот же результат, ответ очевиден, это зависит.

Далибора
источник
28

inтакже проверит наличие унаследованных свойств, чего нельзя сказать о hasOwnProperty.

xavier.seignard
источник
25

Таким образом, hasOwnProperty()не выглядит в прототипе, inно выглядит в прототипе.

Взято из высокопроизводительного Javascript от O'Reilly :

Вы можете определить, есть ли у объекта член экземпляра с заданным именем, используя метод 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», поскольку title является экземпляром объекта; метод возвращает false, когда передается «toString», потому что он не существует в экземпляре. Когда каждое имя свойства используется с оператором in, результат имеет значение true оба раза, поскольку он ищет экземпляр и прототип.

Этьен Ноэль
источник
5

Вы получили несколько действительно хороших ответов. Я просто хочу предложить что-то, что избавит вас от необходимости проверять «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
}

Я узнал этот удивительный совет здесь

asafel
источник
1
более подробное описание: ryanmorr.com/true-hash-maps-in-javascript
darcher
2

Другая форма (для вызова in) перечисляет имена свойств (или ключи) объекта. На каждой итерации переменной присваивается другая строка имени свойства объекта. Обычно необходимо проверить object.hasOwnProperty (переменная), чтобы определить, действительно ли имя свойства является членом объекта или было найдено вместо этого в цепочке прототипов.

 for (myvar in obj) {
     if (obj.hasOwnProperty(myvar)) { ... } }

(из Javascript Крокфорда : хорошие части )

Джахан
источник
5
inОператор отличается от for-inзаявления.
Я ненавижу Ленивых
На самом деле, оба они имеют различное использование в ключевом слове
Джахан
4
Да, inэто ключевое слово. Но ОП спрашивает о конкретном использовании в качестве inоператора. Ваш ответ касается другого использования как части for-inутверждения.
Я ненавижу Ленивых
-3

Первая версия короче (особенно в минимизированном коде, где переменные переименованы)

a in b

против

b.hasOwnProperty(a)

В любом случае, как сказал @AndreMeinhold, они не всегда дают один и тот же результат.

antonjs
источник
1
Было бы лучше иметь это в качестве комментария. :-)
Хлавулека МАС