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

173

Apakah dua pernyataan berikut menghasilkan output yang sama? Apakah ada alasan untuk memilih satu cara ke yang lain?

 if (key in object)

 if (object.hasOwnProperty(key))
Lorraine Bernard
sumber

Jawaban:

181

Hati-hati - mereka tidak akan menghasilkan hasil yang sama.

injuga akan kembali truejika keyditemukan di suatu tempat di rantai prototipe , sedangkan Object.hasOwnProperty(seperti namanya sudah memberitahu kita), hanya akan kembali truejika keytersedia pada objek itu secara langsung ("memiliki" properti).

Andre Meinhold
sumber
3
apa maksudmu sebenarnya in will also return true if key gets found somewhere in the prototype chain. dapatkah Anda menulis contoh? Terima kasih.
Lorraine Bernard
44
@Lor: ({foo:"bar"}).hasOwnProperty("toString")vs"toString" in ({foo:"bar"})
I Hate Lazy
68

Saya akan mencoba menjelaskan dengan contoh lain. Katakanlah kita memiliki objek berikut dengan dua properti:

function TestObj(){
    this.name = 'Dragon';
}
TestObj.prototype.gender = 'male';

Mari kita buat instance dari TestObj:

var o = new TestObj();

Mari kita periksa contoh objek:

console.log(o.hasOwnProperty('name')); // true
console.log('name' in o); // true

console.log(o.hasOwnProperty('gender')); // false
console.log('gender' in o); // true

Kesimpulan:

  • di operator mengembalikan true selalu, jika properti dapat diakses oleh objek, langsung atau dari prototipe

  • hasOwnProperty () mengembalikan true hanya jika properti ada pada instance, tetapi tidak pada prototipe-nya

Jika kita ingin memeriksa bahwa ada beberapa properti pada prototipe, secara logis, kita akan mengatakan:

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

Akhirnya:

Jadi, terkait dengan pernyataan bahwa kedua syarat ini ...

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

... menghasilkan hasil yang sama, jawabannya jelas, itu tergantung.

Dalibor
sumber
28

injuga akan memeriksa properti yang diwarisi, yang tidak berlaku untuk hasOwnProperty.

xavier.seignard
sumber
25

Singkatnya, hasOwnProperty()tidak terlihat di prototipe sementara intidak terlihat di prototipe.

Diambil dari O'Reilly High Performance Javascript :

Anda dapat menentukan apakah suatu objek memiliki anggota instance dengan nama yang diberikan dengan menggunakan metode hasOwnProperty () dan mengirimkan nama anggota tersebut. Untuk menentukan apakah suatu objek memiliki akses ke properti dengan nama yang diberikan, Anda dapat menggunakan operator in. Sebagai contoh:

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

Dalam kode ini, hasOwnProperty () mengembalikan true ketika "title" dilewatkan karena judul adalah turunan objek; metode mengembalikan false ketika "toString" dilewatkan karena tidak ada pada instance. Ketika setiap nama properti digunakan dengan operator in, hasilnya benar dua kali karena mencari instance dan prototipe.

Etienne Noël
sumber
5

Anda mendapat jawaban yang sangat bagus. Saya hanya ingin menawarkan sesuatu yang akan menghemat kebutuhan Anda untuk memeriksa "hasOwnProperty" saat iterasi objek.

Saat membuat objek biasanya orang akan membuatnya dengan cara ini:

const someMap = {}
// equivalent to: Object.create(Object.prototype)
// someMap.constructor will yield -> function Object() { [native code] }

Sekarang, jika Anda ingin mengulang melalui "someMap", Anda harus melakukannya dengan cara ini:

const key
for(key in someMap ){
 if (someMap.hasOwnProperty(key)) { 
   // Do something
 }
}

Kami melakukannya untuk menghindari iterasi dari properti yang diwarisi.

Jika Anda bermaksud membuat objek sederhana yang hanya akan digunakan sebagai "peta" (yaitu pasangan nilai kunci) Anda dapat melakukannya seperti itu:

const newMap = Object.create(null);
// Now, newMap won't have prototype at all.
// newMap.constructor will yield -> undefined

Jadi sekarang akan aman untuk beralih seperti ini:

for(key in cleanMap){
 console.log(key + " -> " + newMap [key]);
 // No need to add extra checks, as the object will always be clean
}

Saya belajar tip yang luar biasa ini di sini

asafel
sumber
1
artikel yang lebih rinci: ryanmorr.com/true-hash-maps-in-javascript
darcher
2

Bentuk lain (dipanggil untuk) menyebutkan nama properti (atau kunci) dari suatu objek. Pada setiap iterasi, string nama properti lain dari objek ditugaskan ke variabel. Biasanya diperlukan untuk menguji object.hasOwnProperty (variabel) untuk menentukan apakah nama properti benar-benar anggota objek atau ditemukan sebagai ganti pada rantai prototipe.

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

(dari Crockford's Javascript: The Good Parts )

Jahan
sumber
5
The inoperator adalah berbeda dari for-inpernyataan.
I Hate Lazy
Sebenarnya keduanya adalah penggunaan kata kunci yang berbeda
Jahan
4
Ya, inadalah kata kunci. Tetapi OP bertanya tentang penggunaan spesifik sebagai inoperator. Jawaban Anda berkaitan dengan penggunaan lain sebagai bagian dari for-inpernyataan.
I Hate Lazy
-3

Versi pertama lebih pendek (terutama dalam kode minified di mana variabel diubah namanya)

a in b

vs.

b.hasOwnProperty(a)

Bagaimanapun, seperti yang dikatakan @AndreMeinhold, mereka tidak selalu menghasilkan hasil yang sama.

antonjs
sumber
1
Akan lebih baik untuk memiliki ini sebagai komentar. :-)
Hlawuleka MAS