Как проверить, имеет ли объект конкретное свойство в JavaScript?


1488

Как проверить, имеет ли объект конкретное свойство в JavaScript?

Рассматривать:

x = {'key': 1};
if ( x.hasOwnProperty('key') ) {
    //Do this
}

Это лучший способ сделать это?


21
Я написал тест jsperf со всеми ответами, чтобы увидеть, какой из них самый быстрый: jsperf.com/dictionary-contains-key
styfle

('propertyName' в объекте)? «собственность есть»: «собственность не существует»
Мохан Рам

1
@styfle спасибо за тест jsperf. inи hasOwnPropertyвышел намного медленнее, чем другие для меня (на 98% медленнее). Я не удивлен, hasOwnPropertyчто я медленнее, но я удивлен in.
evanrmurphy

Ответы:


1424

Я действительно смущен ответами, которые были даны - большинство из них просто неправильно. Конечно, у вас могут быть свойства объекта с неопределенными, нулевыми или ложными значениями. Таким образом, простое сокращение проверки собственности до typeof this[property]или, что еще хуже, x.keyдаст вам полностью вводящие в заблуждение результаты.

Это зависит от того, что вы ищете. Если вы хотите знать, содержит ли объект физически свойство (и оно не приходит откуда-то вверх по цепочке прототипов), тогда object.hasOwnPropertyесть путь. Все современные браузеры поддерживают это. (Это отсутствовало в более старых версиях Safari - 2.0.1 и более ранних - но эти версии браузера редко используются больше.)

Если вы ищете, если у объекта есть свойство, которое является итеративным (когда вы перебираете свойства объекта, оно появится), тогда выполните команду: prop in objectдаст вам желаемый эффект.

Поскольку использование hasOwnProperty- это, вероятно, то, что вам нужно, и, учитывая, что вы можете использовать запасной метод, я представляю вам следующее решение:

var obj = {
    a: undefined,
    b: null,
    c: false
};

// a, b, c all found
for ( var prop in obj ) {
    document.writeln( "Object1: " + prop );
}

function Class(){
    this.a = undefined;
    this.b = null;
    this.c = false;
}

Class.prototype = {
    a: undefined,
    b: true,
    c: true,
    d: true,
    e: true
};

var obj2 = new Class();

// a, b, c, d, e found
for ( var prop in obj2 ) {
    document.writeln( "Object2: " + prop );
}

function hasOwnProperty(obj, prop) {
    var proto = obj.__proto__ || obj.constructor.prototype;
    return (prop in obj) &&
        (!(prop in proto) || proto[prop] !== obj[prop]);
}

if ( Object.prototype.hasOwnProperty ) {
    var hasOwnProperty = function(obj, prop) {
        return obj.hasOwnProperty(prop);
    }
}

// a, b, c found in modern browsers
// b, c found in Safari 2.0.1 and older
for ( var prop in obj2 ) {
    if ( hasOwnProperty(obj2, prop) ) {
        document.writeln( "Object2 w/ hasOwn: " + prop );
    }
}

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


5
@grantwparks Если вы создаете простой плагин-слайдер и хотите проверить наличие элемента параметров, то это может быть больше, чем нужно. Вы можете просто сделать что-то вроде var w = opts.w || 100;. Но если вы что-то делаете в библиотеке, вам, возможно, придется пойти немного дальше в некоторых частях.
Халил Озгюр

@ kralco626: Да, в настоящее время я чувствую, что довольно безопасно использовать hasOwnProperty () - но для действительно безопасного кроссбраузерного решения воспользуйтесь предложением Джона.
Джейкоб

Как насчет временного изменения __proto__на ноль? Простой импл: function hasOwnProperty(obj, prop) { var temp = obj.__proto__; obj.__proto__ = null; var ret = prop in obj; obj.__proto__ = temp; return ret; }( obj.constructor.prototypeследует добавить регистр с ).
средний Джо

2
@Kasztan __proto__нестандартен и не работает в некоторых старых браузерах. И даже с недавним добавлением Object.getPrototypeOfстандарта говорится, что вы все еще не можете изменить прототип существующего объекта.
Мэтт Браун

13
for(prop in object)Цикл перебирает только перечисляемые свойства. Однако prop in objectпроверяет, objectесть ли свойство propгде-то в прототипной цепочке, независимо от того, является ли оно перечислимым или нет.
Ориоль

283

С Underscore.jsили ( даже лучше ) lodash:

_.has(x, 'key');

Какие вызовы Object.prototype.hasOwnProperty, но (а) короче, чтобы набрать, и (б) использует «безопасную ссылку на hasOwnProperty» (т.е. он работает, даже если hasOwnPropertyперезаписан).

В частности, lodash определяет _.hasкак:

   function has(object, key) {
      return object ? hasOwnProperty.call(object, key) : false;
   }
   // hasOwnProperty = Object.prototype.hasOwnProperty

52
Я думаю, это потому, что «добавить эту библиотеку» редко является популярным решением, даже если вопрос касается сложных манипуляций с DOM, а ответ «иди используй jQuery».
Уинфилд Трейл

11
Я понимаю вашу точку зрения, @sudowned, спасибо. Между прочим, если бы кто-то возражал против включения всей библиотеки lodash, можно было бы скомпилировать подкомпоненты или npm install lodash.hasполучить модуль npm с помощью только hasфункции, которая компилирует до 175 байтов при минимизации. Также полезно взглянуть на то, lodash.has/index.jsкак работает очень популярная и надежная библиотека.
Брайан М. Хант

9
и lodash's версии работают с этим: .has(undefined, 'someKey') => falseпока underscoreвозвращаетсяundefined
Брэд Паркс

13
Всем жаловаться на добавление в lodashкачестве «еще одной» зависимости: это довольно распространенная (если не самая распространенная) библиотека для такого рода вещей. Получайте удовольствие, изобретая велосипед.
Прииду Нимре

11
Даже если вы хотите заново изобрести колесо, проверить существующие колеса - неплохая идея.
AturSams

147

Что о?

var x = {'key': 1};

if ('key' in x) {
    console.log('has');
}

13
Просто отметим, что он работает с «объектами» в узком смысле, поэтому он объявлен как {} или создан с использованием конструктора, он не принимает массивы или примитивы. Не то, чтобы ОП требовало этого, но некоторые другие ответы представляют более широкие методы (работа с массивами, строками и т. Д.)
Данубский моряк,

@ РСТȢѸФХѾЦЧШЩЪЫЬѢѤЮѦѪѨѬѠѺѮѰѲѴ спасибо за указание на это (в принятом ответе нет подробностей о том, почему следует использовать inоператор или нет. Также обратите внимание, что у inоператора есть отличная поддержка браузера IE 5.5+, Chrome 1.0+, Firefox 1.0+, Safari 3.0+ stackoverflow.com/questions/2920765/…
Adrien Be

2
Оператор inтакже проверяет свойства прототипа, в то время как hasOwnPropertyвыполняет итерацию только пользовательских свойств. Ссылка: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
adi518

2
'key' in x сделать работу с массивами. Доказательство: stackoverflow.com/questions/33592385/…
CosmoMyzrailGorynych

Похоже, лучший и самый короткий вариант
user365314

132

Примечание : следующее в настоящее время в значительной степени устарело благодаря строгому режиму, и hasOwnProperty. Правильное решение - использовать строгий режим и проверять наличие свойства с помощью obj.hasOwnProperty. Этот ответ предшествует обеим этим вещам, по крайней мере, так широко реализованным (да, это так давно). Возьмите следующее как историческое примечание.


Имейте в виду, что undefined(к сожалению) не является зарезервированным словом в JavaScript, если вы не используете строгий режим. Следовательно, кто-то (очевидно, кто-то еще) может иметь грандиозную идею переопределить его, взломав код.

Поэтому более надежный метод заключается в следующем:

if (typeof(x.attribute) !== 'undefined')

С другой стороны, этот метод гораздо более многословен, а также медленнее. : - /

Распространенной альтернативой является обеспечение того, что undefinedона фактически не определена, например, путем помещения кода в функцию, которая принимает дополнительный вызываемый параметр undefined, которому не передано значение. Чтобы убедиться, что значение не передано, вы можете сразу вызвать его самостоятельно, например:

(function (undefined) {
     your code 
    if (x.attribute !== undefined)
         mode code 
})();

6
Просто любопытно, так void 0как определено вернуть каноническое undefined, можно ли это сделать x.attribute !== void 0?
Брайан М. Хант

1
Брайан: Я не эксперт, но это похоже на умный способ сделать все правильно.
Кристофер Смит

37
Если знаменитый «кто-то еще» переопределил, что такое undefined, я думаю, что лучшим способом было бы переписать этот код.
Оскар Холмкрац

3
Лучше всего иметь твердую неопределенную переменную var, работать в закрытии и иметь непревзойденную сигнатуру функции:(function (undefined) { // undefined is actually undefined here })();
bgusach

1
@evanrmurphy Не используйте это, оно серьезно устарело (см. примечание в начале моего ответа).
Конрад Рудольф

55
if (x.key !== undefined)

Армин Роначер, кажется, уже победил меня , но:

Object.prototype.hasOwnProperty = function(property) {
    return this[property] !== undefined;
};

x = {'key': 1};

if (x.hasOwnProperty('key')) {
    alert('have key!');
}

if (!x.hasOwnProperty('bar')) {
    alert('no bar!');
}

Более безопасный, но медленнее решение, как было указано на Konrad Rudolph и Armin Ronacher будет:

Object.prototype.hasOwnProperty = function(property) {
    return typeof this[property] !== 'undefined';
};

2
Я не думаю, что это достаточно хорошо. x.hasOwnProperty('toString') === true;
Джо Симмонс

Не просить не согласиться, но понять. Есть ли точка, в которой x.hasOwnProperty будет возвращать что-либо, кроме логического true или false? Если нет, то код, как размещено, должен работать каждый раз. Я полагаю, может быть, если бы метод был переопределен, но тогда полагаться на результат никогда не было бы надежным, если вы не знаете переопределяющий метод.
enobrev

1
Я думаю, что у нас есть недопонимание. Я имею в виду, что используя ваш метод, он сказал бы, что toString - это его собственное свойство, но это не так.
Джо Симмонс

3
Object.prototypeуже есть встроенный, правильно hasOwnProperty. Перезаписать его неверной реализацией (1. Свойства могут иметь значение undefined, 2. Это даст ложные срабатывания для унаследованных свойств) - просто ужасно плохая идея. Неправильные ответы могут и должны быть удалены. Я не знаю, сможете ли вы сделать это в сентябре 2008 года, когда увидели ответ Ресига , так что комментируйте, чтобы предложить сделать это сейчас.
Ти Джей Краудер

36

Вы можете использовать inоператор, чтобы проверить, существует ли свойство объекта:

x = {'key': 1};
alert("key" in x);

Вы также можете просмотреть все свойства объекта с помощью for - inцикла, а затем проверить наличие определенного свойства:

for (prop in x) {
    if (prop == "key") {
        //Do something
    }
}

Вы должны рассмотреть, является ли это свойство объекта перечислимым или нет, потому что не перечисляемые свойства не будут отображаться в for-inцикле. Кроме того, если свойство enumerable скрывает неперечислимое свойство прототипа, оно не будет отображаться в Internet Explorer 8 и более ранних версиях.

Если вы хотите получить список всех свойств экземпляра, перечислимых или нет, вы можете использовать

Object.getOwnPropertyNames(x);

Это вернет массив имен всех свойств, которые существуют в объекте.

Наконец, вы можете использовать оператор typeof для прямой проверки типа данных свойства объекта:

if (typeof x.key == "undefined") {
    alert("undefined");
}

Если свойство не существует в объекте, оно вернет строку undefined. В противном случае он вернет соответствующий тип свойства. Тем не менее, обратите внимание, что это не всегда правильный способ проверки, имеет ли объект свойство или нет, потому что у вас может быть свойство, для которого установлено значение undefined, и в этом случае при использовании по- typeof x.keyпрежнему будет возвращаться значение true (даже если ключ по-прежнему в объекте).

Обновление: Вы можете проверить, существует ли свойство, сравнивая с неопределенным свойством javascript

if (x.key === undefined) {
    alert("undefined");
}

Это должно работать, если ключ не был специально установлен для undefinedобъекта x


Ваша часть обновления неверна. Пожалуйста, посмотрите здесь: jsfiddle.net/sbgg04yg
Number945

Обновлен, чтобы показать сценарии, в которых сравнение с неопределенным свойством JavaScript может завершиться неудачей
goonerify

31

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

hasOwnPropertyвозвращает true, если переданное ему имя атрибута было добавлено к объекту. Он полностью не зависит от фактического значения, назначенного ему, которое может быть точно undefined.

Следовательно:

var o = {}
o.x = undefined

var a = o.hasOwnProperty('x')  // a is true
var b = o.x === undefined // b is also true

Однако:

var o = {}

var a = o.hasOwnProperty('x')  // a is now false
var b = o.x === undefined // b is still true

Проблема в том, что происходит, когда объект в цепочке прототипов имеет атрибут со значением undefined? hasOwnPropertyбудет ложным за это, и так будет !== undefined. Пока for..inчто все равно перечислю это в перечислении.

Суть в том, что нет кросс-браузерного способа (поскольку Internet Explorer не предоставляет __prototype__) для определения того, что определенный идентификатор не был прикреплен к объекту или чему-либо в его цепочке прототипов.


24

Если вы ищете недвижимость, тогда «НЕТ». Ты хочешь:

if ('prop' in obj) { }

В общем случае вам не важно, является ли свойство прототипом или объектом.

Однако, поскольку вы использовали «ключ» в своем примере кода, похоже, вы рассматриваете объект как хеш, и в этом случае ваш ответ будет иметь смысл. Все ключи хешей будут свойствами объекта, и вы избежите дополнительных свойств, предоставленных прототипом.

Ответ Джона Резига был очень исчерпывающим, но я подумал, что он не ясен. Особенно, когда использовать «prop» в obj ».


1
Обратите внимание, что у inоператора есть отличная поддержка браузера IE 5.5+, Chrome 1.0+, Firefox 1.0+, Safari 3.0+ stackoverflow.com/questions/2920765/…
Adrien Be

Как указано в другом комментарии, касающемся использования inоператора: «он работает с« объектами »в узком смысле, поэтому объявлен как {} или создан с помощью конструктора, он не принимает массивы или примитивы. Не то, что OP этого требовал, но некоторые другие ответы представляют более широкие методы (работа с массивами, строками и т. д.) »
Adrien Be

1
Комментировать, потому что я был дважды проголосовал без комментариев. Но мне все еще нравится мой ответ. Возможно, тот, кто сделал это, хотел получить «исчерпывающий» ответ для всех способов проверки всех типов свойств. Но мой ответ концептуален и для этого - лаконичен. Re: Адриен Бе, неисчислимое свойство - это свойство, которое не предназначено для общего пользовательского контекста, поэтому концептуально «в» это нормально;)
Gerard ONeill

16

Для тестирования простых объектов используйте: if (obj[x] !== undefined)

Если вы не знаете, какой тип объекта он использует: if (obj.hasOwnProperty(x))

Все остальные варианты медленнее ..

подробности

Оценка производительности 100 000 000 циклов под Nodejs для 5 вариантов, предложенных другими здесь:

function hasKey1(k,o) { return (x in obj); }
function hasKey2(k,o) { return (obj[x]); }
function hasKey3(k,o) { return (obj[x] !== undefined); }
function hasKey4(k,o) { return (typeof(obj[x]) !== 'undefined'); }
function hasKey5(k,o) { return (obj.hasOwnProperty(x)); }

Оценка говорит нам, что, если мы не хотим специально проверять цепочку прототипов объекта, а также сам объект, мы не должны использовать общую форму: if (X in Obj)... она в 2-6 раз медленнее в зависимости от варианта использования

hasKey1 execution time: 4s 510.427785ms
hasKey2 execution time: 0s 904.374806ms
hasKey3 execution time: 0s 760.336193ms
hasKey4 execution time: 0s 935.19901ms
hasKey5 execution time: 2s 148.189608ms

В итоге, если ваш Obj не обязательно является простым объектом и вы хотите избежать проверки цепочки прототипов объекта и убедиться, что x принадлежит непосредственно Obj, используйте 'if (obj.hasOwnProperty (x)) ...'.

В противном случае, если вы используете простой объект и не беспокоитесь о цепочке прототипов объекта, использование if (typeof(obj[x]) !== 'undefined')...является самым безопасным и быстрым способом.

Если вы используете простой объект в качестве хеш-таблицы и никогда не делаете ничего странного, я бы использовал его, так if (obj[x])...как считаю его более читабельным.

Радоваться, веселиться.


15

Да, это так :) Я думаю, вы также можете сделать, Object.prototype.hasOwnProperty.call(x, 'key')что также должно работать, если xесть свойство называется hasOwnProperty:)

Но это проверяет собственные свойства. Если вы хотите проверить, есть ли у него свойство, которое также может быть унаследовано, вы можете использовать его typeof x.foo != 'undefined'.


14
if (typeof x.key != "undefined") {

}

Потому что

if (x.key)

не удается, если x.keyразрешается false(например, x.key = "").


Не будет правильно. Попробуйте следующий объект, const x = {key: undefined};который вернет false с этим решением, в то время как x.hasOwnProperty('key')); // trueи Reflect.has(x, 'key')); // true. Свойство действительно существует, но значение есть undefined.
Уилт


10

ОК, похоже, у меня был правильный ответ, если только вы не хотите наследовать свойства:

if (x.hasOwnProperty('key'))

Вот некоторые другие опции для включения унаследованных свойств:

if (x.key) // Quick and dirty, but it does the same thing as below.

if (x.key !== undefined)

4
Предупреждение x.hasOwnProperty ('key') может быть истинным, в то время как x.key! == undefined не является истинным.
AnthonyWJones

4
Для var x = { key: false };в x.keyметоде было бы неправильно.
Марк К Коуэн

2
если (x.key) не так, как если бы x = {key: 0}, проверка не пройдет.
SomeUser

10

Не делайте этого object.hasOwnProperty(key)), это действительно плохо, потому что эти методы могут быть затенены свойствами рассматриваемого объекта - подумайте { hasOwnProperty: false }- или объект может быть нулевым объектом(Object.create(null)) .

Лучший способ это сделать Object.prototype.hasOwnProperty.call(object, key)или:

const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
/* or */
import has from 'has'; // https://www.npmjs.com/package/has
// ...
console.log(has.call(object, key));

3
Я согласен с этим методом, и это должен быть принятый ответ, так как это самый безопасный способ при сохранении производительности! eslint.org/docs/rules/no-prototype-builtins говорит: «Например, для веб-сервера было бы небезопасно анализировать входные данные JSON от клиента и вызывать hasOwnProperty непосредственно для результирующего объекта, поскольку злонамеренный клиент мог отправить значение JSON. как {"hasOwnProperty": 1} и вызвать сбой сервера. "
Арман

7

Еще один относительно простой способ использования Object.keys. Это возвращает, arrayчто означает, что вы получаете все функции массива.

var noInfo = {};
var info = {something: 'data'};

Object.keys(noInfo).length //returns 0 or false
Object.keys(info).length //returns 1 or true

Хотя мы находимся в мире с отличной поддержкой браузера. Поскольку этот вопрос настолько старый, я подумал, что добавлю это: Это безопасно для использования с JS v1.8.5


Правильно, но что, если вы хотите знать, есть ли у информации свойство с именем что-то другое? То, что думают, это то, что ищет OP.
Викторио Берра

2
Тогда вы бы сделалиObject.keys(info).indexOf('someotherthing') !== -1
Hippietrail

7

hasOwnProperty "может использоваться, чтобы определить, имеет ли объект указанное свойство как прямое свойство этого объекта; в отличие от оператора in , этот метод не проверяет цепочку прототипов объекта".

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

Если вы хотите определить, существует ли свойство в цепочке прототипов, в которой вы хотите использовать, например:

if( prop in object ){ // do something }

Надеюсь, это поможет.


Я получаю оператор «Не могу использовать» для поиска «prop» в myObject »
Victorio Berra

3

С риском массового понижения голосов, вот еще один вариант для конкретного случая. :)

Если вы хотите проверить член на объекте и хотите узнать, было ли для него установлено что-то отличное от:

  • «»
  • ложный
  • значение NULL
  • не определено
  • 0 ...

тогда вы можете использовать:

var foo = {};
foo.bar = "Yes, this is a proper value!";
if (!!foo.bar) {
        // member is set, do something
}

Компактный и удобный
Фредерик Витте

Линтеру это не понравится: eslint.org/docs/rules/no-extra-boolean-cast
Уилт

2

ECMA Script 6 решение с отражением. Создайте обертку как:

/**
Gets an argument from array or object.
The possible outcome:
- If the key exists the value is returned.
- If no key exists the default value is returned.
- If no default value is specified an empty string is returned.
@param obj    The object or array to be searched.
@param key    The name of the property or key.
@param defVal Optional default version of the command-line parameter [default ""]
@return The default value in case of an error else the found parameter.
*/
function getSafeReflectArg( obj, key, defVal) {
   "use strict";
   var retVal = (typeof defVal === 'undefined' ? "" : defVal);
   if ( Reflect.has( obj, key) ) {
       return Reflect.get( obj, key);
   }
   return retVal;
}  // getSafeReflectArg

Это лучший способ сделать это, когда вы нацеливаетесь на> = ES6?
hippietrail

1
Imho, это самый короткий и самый простой ответ, но, возможно, не самый быстрый в исполняемом коде. Но скорость не проблема (больше).
Вред

2

Существует метод «hasOwnProperty» для объекта, но не рекомендуется вызывать этот метод напрямую, потому что иногда объект может иметь значение null или какое-либо свойство существует для объекта, например: { hasOwnProperty: false }

Так что лучшим способом будет:

// good
var obj = {"bar": "here bar desc"}
console.log(Object.prototype.hasOwnProperty.call(obj, "bar"));

// best
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
console.log(has.call(obj, "bar"));


2

Вы можете использовать следующие подходы:

var obj = {a:1}
console.log('a' in obj)               //1
console.log(obj.hasOwnProperty('a'))  //2
console.log(Boolean(obj.a))         //3

Разница между следующими подходами заключается в следующем:

  1. При первом и третьем подходе мы ищем не только объект, но и его цепочку прототипов. Если объект не имеет свойства, но свойство присутствует в его цепочке прототипов, он собирается дать значение true.

 var obj = {
      a:2,
      __proto__ :{b:2}
    }

    console.log('b' in obj)
    console.log(Boolean(obj.b))

  1. 2-й подход будет проверять только свои свойства. Ex -

var obj = {
      a:2,
      __proto__ :{b:2}
    }

    console.log(obj.hasOwnProperty('b'))

  1. Разница между 1-м и 3-м заключается в том, что если есть свойство, значение которого не определено, 3-й подход даст значение false, а первый даст значение true.

var obj = {
      b : undefined
    }
    console.log(Boolean(obj.b))
    console.log('b' in obj);


1

Вам нужно использовать метод object.hasOwnProperty(property). Возвращает true, если объект имеет свойство, и false, если объект не имеет.


-1

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

x = {'key': 1};
y = 'key';
x[y];

Чем это концептуально отличается от простого тестирования x ['key']? И чем это отличается от x.key? Кроме доступа к массиву, конечно ..
Джерард ONeill

-1

Зачем слишком усложнять вещи, когда вы можете сделать:

var isProperty =  (objectname.keyname || "") ? true : false;

Просто и понятно в большинстве случаев ...


Самым простым из них является var isProperty = !! objectname.keyname;
Джон

Если объект выглядит следующим образом, const objectName = { keyname: false };он должен вернуть true, так keynameкак является свойством objectname. Но так как значение ложно, это вернет ложь с этой логикой.
Уилт
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.