JavaScript: Определен ли член? - PullRequest
20 голосов
/ 17 декабря 2011

Мне кажется, что есть четыре различных способа определить, есть ли у определенного объекта (например, foo) заданное свойство (например, bar):

  1. if (foo.hasOwnProperty(bar)) {
  2. if ('bar' in foo) {
  3. if (typeof foo.bar !== 'undefined') {
  4. if (foo.bar === undefined) {

Чтобы определить, есть ли свойство с именем "bar" вобъект foo, все три из этих утверждений эквивалентны?Есть ли какая-то тонкая семантика, которую я не знаю, которая отличает какое-либо из этих трех утверждений?

Ответы [ 6 ]

17 голосов
/ 17 декабря 2011

Нет, они совершенно разные.Пример:

foo = {bar: undefined};
Object.prototype.baz = undefined;
Object.prototype.bing = "hello";

Тогда:

(typeof foo.bar != "undefined")  === false
('bar' in foo)                   === true
(foo.hasOwnProperty('bar'))      === true


(typeof foo.baz != "undefined")  === false
('baz' in foo)                   === true
(foo.hasOwnProperty('baz'))      === false


(typeof foo.bing != "undefined") === true
('bing' in foo)                  === true
(foo.hasOwnProperty('bing'))     === false

По логике:

  • foo.hasOwnProperty('bar') подразумевает 'bar' in foo
  • typeof foo.bar != "undefined" подразумевает 'bar' in foo
  • Но это единственные выводы, которые вы можете сделать;никакие другие последствия не являются универсально верными, как показывают приведенные выше контрпримеры.
10 голосов
/ 17 декабря 2011

Это все разные:

  1. foo.hasOwnProperty('bar') сообщает вам, имеет ли foo свойство и не выполняет поиск по цепочке прототипов.

  2. 'bar' in foo проверяет цепочку прототипов и возвращает true, когда находит свойство bar в любом объекте вдоль цепочки.

  3. typeof foo.bar != 'undefined' возвращает true, если foo или какой-либо объект в его цепочке прототипов имеет свойство bar и его значение не равно undefined.

Вот пример, демонстрирующий эти различия:

var foo1 = { 'bar1': 10, 'bar2': undefined };
function ctor() {}
ctor.prototype = foo1;
var foo2 = new ctor();
foo2.bar3 = 20;

console.log(foo2.hasOwnProperty('bar1')); // false
console.log(foo2.hasOwnProperty('bar2')); // false
console.log(foo2.hasOwnProperty('bar3')); // true
console.log(foo2.hasOwnProperty('bar4')); // false

console.log('bar1' in foo2); // true
console.log('bar2' in foo2); // true
console.log('bar3' in foo2); // true
console.log('bar4' in foo2); // false

console.log(typeof foo2.bar1 != 'undefined'); // true
console.log(typeof foo2.bar2 != 'undefined'); // false
console.log(typeof foo2.bar3 != 'undefined'); // true
console.log(typeof foo2.bar4 != 'undefined'); // false
2 голосов
/ 17 декабря 2011

Действительно, между различными методами / ключевыми словами есть некоторые тонкие различия.

  1. foo.hasOwnProperty('bar') возвращает значение true, только если свойство 'bar' определено в самом объекте foo.Другие свойства, такие как 'toString', вернут false, однако, поскольку они определены в цепочке прототипов.

  2. Оператор ключевого слова in возвращает значение true, если указанное свойство находится в указанном объекте.,И 'bar' in foo, и 'toString' in foo вернули бы true.

  3. Поскольку вы проверяете состояние свойства, результат будет true, когда bar не определен для foo и когда barопределено, но значение установлено на undefined.

2 голосов
/ 17 декабря 2011
'bar' in foo 

будет искать цепь прототипов в любом месте. Тестирование, чтобы увидеть, будет ли foo.bar! == undefined также возвращать true, если bar находится где-нибудь в цепочке прототипов foo, но помните, если bar имеет значение , определенное для foo, и установите на не определено, это вернет false.

hasOwnProperty более разборчивый - он вернет только true, если bar определено как прямое свойство foo.

за MDN

Каждый объект, произошедший от Object, наследует метод hasOwnProperty. Этот метод может использоваться, чтобы определить, имеет ли объект указанное свойство как прямое свойство этого объекта; в отличие от в оператор, этот метод не проверяет прототип объекта цепь. * * тысяча двадцать-одна

2 голосов
/ 17 декабря 2011

Одно отличие состоит в том, что метод 1 будет проверять только объект foo на панель свойств, тогда как два последних метода также проверяют прототип на унаследованное свойство.

0 голосов
/ 17 декабря 2011

Чтобы добавить к тому, что сказали другие, если вы просто хотите узнать, существует ли свойство и имеет ли оно не ложное значение (не undefined, null, false, 0, "", NaN и т. Д.), Вы можете просто сделать это:

if (foo.bar) {
     // code here
}

До тех пор, пока значения Falsey не будут вам интересны для ваших конкретных обстоятельств, этот ярлык сообщит вам, была ли для переменной установлена ​​какая-то полезная для вас или нет.

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

if ('bar' in foo) {
    // code here
}

Можно также использовать что-то похожее в аргументах функции (опять же, если значение Falsey не то, что вас волнует):

function foo(bar) {
    if (bar) {
        // bar was passed and has some non-falsey value
    }
}
...