2011-12-16 16 views
20

Mi sembra che ci sono quattro modi diversi è possibile determinare se un determinato oggetto (ad esempio foo) ha una data proprietà (ad esempio bar) definiti:JavaScript: è stato definito un membro?

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

Per determinare se esiste un il nome "bar" nell'oggetto foo, sono tutte e tre le istruzioni equivalenti? C'è qualche semantica sublime che non conosco che rende diverse queste tre affermazioni?

+1

da segnalare che, a meno che qualcuno ha sovrascritto la variabile globale 'undefined', 3 può essere fatto anche come' se (foo.bar == non definito) {'. – Domenic

risposta

17

No, sono completamente diversi. Esempio:

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

Poi:

(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 

Logic-saggio:

  • foo.hasOwnProperty('bar') implica 'bar' in foo
  • typeof foo.bar != "undefined" implica 'bar' in foo
  • Ma quelle sono le uniche conclusioni è possibile disegnare; nessun'altra implicazione è universalmente vera, come mostrano i precedenti controesempi.
+1

+1 - Ho dimenticato di considerare la barra inattiva, ma impostata su undefined –

2

una differenza è che, il metodo 1 controllerà solo l'oggetto foo per la barra delle proprietà mentre gli ultimi due metodi controlleranno anche il prototipo per la proprietà ereditata.

2
'bar' in foo 

guarderanno ovunque la catena del prototipo. Test per vedere se foo.bar! == undefined tornerà anche vero se bar è ovunque nel foo s' prototipo catena, ma ricordo se bar è definita su foo, e insieme a indefinito, questo tornerà falso.

hasOwnProperty è più esigente - restituirà solo true è bar è definito come proprietà diretta di foo.

Per MDN

Ogni oggetto discendeva da Object eredita il metodo hasOwnProperty. Questo metodo può essere utilizzato per determinare se un oggetto ha la proprietà specificata come proprietà diretta di tale oggetto; a differenza dell'operatore in , questo metodo non controlla la catena del prototipo dell'oggetto .

10

Questi sono tutti diversi:

  1. foo.hasOwnProperty('bar') ti dice se foo ha la proprietà e non esegue di ricerca lungo la catena di prototipi.

  2. 'bar' in foo controlla la catena del prototipo e restituisce true quando trova la proprietà bar in qualsiasi oggetto lungo la catena.

  3. typeof foo.bar != 'undefined' restituisce vero se foo o qualsiasi altro oggetto lungo la sua catena di prototipi ha proprietà bar e il suo valore non è undefined.

Ecco un esempio che illustra queste differenze:

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

Ci sono infatti alcune sottili differenze tra i vari metodi/parole chiave.

  1. foo.hasOwnProperty('bar') restituisce vero solo se la proprietà 'bar' è definito sull'oggetto foo stesso. Altre proprietà, come 'toString', restituiranno false tuttavia poiché sono definite sulla catena del prototipo.

  2. L'operatore di parole chiave in restituisce true se la proprietà specificata si trova nell'oggetto specificato. Entrambi 'bar' in foo e 'toString' in foo restituirebbero true.

  3. Poiché si controlla lo stato della proprietà, il risultato sarà true quando la barra non è definita su foo e quando la barra è definita ma il valore è impostato su undefined.

0

Per aggiungere a ciò che altri hanno detto, se si vuole solo sapere se una proprietà esiste e ha un valore non Falsey (non undefined, null, false, 0, "", NaN, ecc ...), si può solo fare questo:

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

finché valori Falsey non sono interessanti per voi per il vostro particolare circostanza, questa scorciatoia vi dirà se la variabile è stata impostata a qualcosa di utile per voi oppure no.

Se volete sapere se la proprietà esiste sull'oggetto in alcun modo, ho trovato questo la più utile, breve e leggibile:

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

Si può anche utilizzare qualcosa di simile su argomenti di funzione (di nuovo come finché un valore Falsey non è qualcosa che ti interessano):!

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