Обнаружение объектов JavaScript: синтаксис точки по сравнению с ключевым словом 'in'

Я видел два способа определить, реализует ли UA конкретное свойство JS: if(object.property) и if('property' in object).

Я хотел бы услышать мнения о том, что лучше, а главное, почему. Один однозначно лучше другого? Есть ли больше, чем просто эти два способа сделать обнаружение свойств объекта? Пожалуйста, включите поддержку браузера, подводные камни, скорость выполнения и т.д., А не эстетику.

Изменить: Читателям рекомендуется запускать тесты на jsperf.com/object-detection

Ответ 1

  • if(object.property)

    выйдет из строя в тех случаях, когда он не установлен (что вам и нужно), и в случаях, когда оно было установлено на какое-либо значение ложности, например. undefined, null, 0 и т.д. (это не то, что вы хотите).

    var object = {property: 0};
    if(object.isNotSet) { ... } // will not run
    if(object.property) { ... } // will not run
    
  • if('property' in object)

    немного лучше, так как он действительно вернет, действительно ли объект имеет свойство, а не просто глядя на его значение.

    var object = {property: 0};
    if('property' in object) { ... } // will run
    if('toString' in object) { ... } // will also run; from prototype
    
  • if(object.hasOwnProperty('property'))

    еще лучше, так как это позволит вам различать свойства экземпляра и свойства прототипа.

    var object = {property: 0};
    if(object.hasOwnProperty('property')) { ... } // will run
    if(object.hasOwnProperty('toString')) { ... } // will not run
    

Я бы сказал, что производительность здесь не такая уж большая, если вы не проверяете тысячи раз в секунду, но в этом случае вы должны рассмотреть другую структуру кода. Все эти функции/синтаксисы поддерживаются недавними браузерами, hasOwnProperty также существует уже давно.


Изменить: Вы также можете сделать общую функцию для проверки существования свойства, передав что-либо (даже объекты, не являющиеся объектами), в качестве объекта, подобного этому:

function has(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
}

Теперь это работает:

has(window, 'setTimeout'); // true

даже если window.hasOwnProperty === undefined (что имеет место в IE версии 8 или ниже).

Ответ 2

Это действительно зависит от того, чего вы хотите достичь. Вы говорите о объектах хоста (например, window и узлах DOM)? Если это так, самая безопасная проверка typeof, которая работает для всех объектов хоста, о которых я знаю:

 if (typeof object.property != "undefined") { ... }

Примечания:

  • Избегайте object.hasOwnProperty() для объектов хоста, потому что объекты-хосты не обязаны наследовать от Object.prototype и, следовательно, могут не иметь метода hasOwnProperty() (и, действительно, в IE < 9, как правило, нет).
  • Простое булевое принуждение (например, if (object.property) { ... }) является плохим испытанием существования свойства, поскольку оно даст ложные отрицания для значений фальши. Например, для пустой текстовой области if (textarea.selectionStart) { ... } не будет выполнять блок, даже если свойство существует. Кроме того, некоторые свойства объекта хоста вызывают ошибку в более старых версиях IE при попытке принуждения к логическому (например, var xhr = new ActiveXObject("Microsoft.XMLHTTP"); if (xhr.responseXML) { ... }).
  • Оператор in является лучшим испытанием существования свойства, но в очередной раз нет гарантий относительно его поддержки в хост-объектов.
  • Я рекомендую не рассматривать производительность для такого рода задач. Выберите самый безопасный вариант для своего проекта и только оптимизируйте его позже. Почти наверняка будут гораздо лучшие кандидаты на оптимизацию, чем проверки на существование.

Для получения дополнительной информации об этом, я рекомендую эту замечательную статью Peter Michaux.

Ответ 3

Определенно if ('property' in object) - правильный путь. Это фактически проверяет, находится ли свойство в объекте (или в его цепочке прототипов, подробнее об этом ниже).

if (object.property), с другой стороны, будет принуждать "свойство" к значению истины/плотности. Если свойство не установлено, оно вернет "undefined", которое будет принудительно введено в false и, похоже, будет работать. Но это также не сработает для ряда других заданных значений свойств. javascript, как известно, несовместим с тем, что он считает правдивым и ложным.

Наконец, как я уже сказал выше, 'property' in 'object' вернет true, если он находится где угодно в цепочке прототипов. Если вы хотите проверить, что на самом объекте, а не где-то выше в цепочке, вы используете метод hasOwnProperty следующим образом:

if (object.hasOwnProperty('property')) ...

Ответ 4

Первый будет терпеть неудачу, если "property" false. Чтобы убедиться, что на самом деле существует свойство, вам нужно проверить, что object.property !== undefined, или использовать ключевое слово.

[изменить]

Существует также функция hasOwnProperty, но я никогда не использовал ее, поэтому я не могу много говорить об этом. Хотя я думаю, что он не вернет true, если свойство задано в прототипе, который иногда вам нужен, в другие моменты, который вам не нужен.

Ответ 5

Это позволяет использовать window.hasOwnProperty как ссылающийся на себя или что-то еще, независимо от вашего узла сценариев.

// No enclosing functions here
if (!('hasOwnProperty' in this))
    function hasOwnProperty(obj, prop) {
        var method = Object.prototype.hasOwnProperty;
        if (prop === undefined)
            return method.call(this, obj);
        return method.call(obj, prop);
    }

//Example of use
var global = global || this; //environment-agnostic way to get the global object
var x = 'blah';
WScript.Echo(global.hasOwnProperty('x') ? 'true' : 'false'); //true

//Use as non-object method
var y = { z: false };
WScript.Echo(hasOwnProperty(y, 'z') ? 'true' : 'false'); //true
WScript.Echo(hasOwnProperty(y, 'w') ? 'true' : 'false'); //false

// true ಠ_ಠ
WScript.Echo(hasOwnProperty(global, 'hasOwnProperty') ? 'true' : 'false');