MyObj.hasOwnProperty (prop) yerine neden Object.prototype.hasOwnProperty.call (myObj, prop) kullanıyorsunuz?


107

Doğru anlarsam, JavaScript'teki her nesne, Nesne prototipinden miras alır; bu, JavaScript'teki her nesnenin, prototip zinciri aracılığıyla hasOwnProperty işlevine erişimi olduğu anlamına gelir.

RequireJS'nin kaynak kodunu okurken bu işleve rastladım:

function hasProp(obj, prop) {
    return hasOwn.call(obj, prop);
}

hasOwnbir referanstır Object.prototype.hasOwnProperty. Bu işlevi şu şekilde yazmanın pratik bir farkı var mı?

function hasProp(obj, prop) {
    return obj.hasOwnProperty(prop);
}

Ve biz oradayken, neden bu işlevi tanımlıyoruz? (Küçük) performans kazanımları için sadece kısayollar ve özellik erişiminin yerel önbelleğe alınması sorunu mu yoksa hasOwnProperty'nin bu yönteme sahip olmayan nesnelerde kullanılabileceği durumları mı kaçırıyorum?

Yanıtlar:


113

[Örneklerim arasında] herhangi bir pratik fark var mı?

Kullanıcı, Object.create(null)bir null [[Prototype]]zinciri olan ve bu nedenle hasOwnProperty()üzerinde bulunmayan bir JavaScript nesnesine sahip olabilir . İkinci formunuzu kullanmak bu nedenle işe yaramaz.

Aynı zamanda daha güvenli Object.prototype.hasOwnProperty()(ve ayrıca daha kısa) bir referanstır .

Birinin yapmış olabileceğini hayal edebilirsiniz ...

var someObject = {
    hasOwnProperty: function(lol) {
        return true;
    }
};

hasProp(someObject)İkinci örneğiniz gibi uygulanmış olsaydı bu bir başarısızlık olurdu (bu yöntemi doğrudan nesne üzerinde bulur ve delege edilmek yerine onu çağırır Object.prototype.hasOwnProperty).

Ancak birisinin Object.prototype.hasOwnPropertyreferansı geçersiz kılma olasılığı düşüktür .

Ve biz oradayken, neden bu işlevi tanımlıyoruz?

Yukarıyı görmek.

Bu sadece kısayollar ve (küçük) performans kazançları için mülk erişiminin yerel önbelleğe alınması meselesi mi?

Zincirin takip edilmesi gerekmediğinden teoride daha hızlı hale getirebilir [[Prototype]], ancak bunun ihmal edilebilir olduğundan şüpheleniyorum ve uygulamanın nedeni bu değil .

... ya hasOwnPropertyda bu yönteme sahip olmayan nesnelerde kullanılabilecek herhangi bir durumu kaçırıyor muyum ?

hasOwnProperty()var Object.prototype, ancak geçersiz kılınabilir. Her yerel JavaScript nesnesi (ancak ana nesnelerin bunu takip etmeleri garanti edilmez, RobG'nin ayrıntılı açıklamasına bakın ) Object.prototypeönceki zincirdeki son nesnesine sahiptir null(tabii ki tarafından döndürülen nesne hariç Object.create(null)).


Mantığınız muhtemelen doğrudur ama bence naziksiniz. Need.js'nin yazarları hasOwnProperty'nin geçersiz kılınmış olabileceğini düşünürse (ki bu son derece olası değildir), o zaman tüm yerleşik yöntemleri bu şekilde çağırmaları gerekir (belki de yaparlar).
RobG

@Periback Gerçekten mi? Desteklediğinden oldukça emindim.
alex

1
Sık kullanılırsa ES6 kısayolu. const hasProp = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
Richard Ayotte

15

Doğru anlarsam, JavaScript'teki her nesne, Nesne prototipinden miras alır

Tüyleri bölmek gibi görünebilir, ancak JavaScript (ECMAScript uygulamaları için genel terim) ve ECMAScript (JavaScript uygulamaları için kullanılan dil ) arasında bir fark vardır . JavaScript'i değil, miras şemasını tanımlayan ECMAScript'tir, bu nedenle yalnızca yerel ECMAScript nesnelerinin bu miras şemasını uygulaması gerekir.

Çalışan bir JavaScript programı, en azından yerleşik ECMAScript nesnelerinden (Nesne, İşlev, Sayı, vb.) Ve muhtemelen bazı yerel nesnelerden (örneğin işlevler) oluşur. Ayrıca bazı ana bilgisayar nesneleri de olabilir (bir tarayıcıdaki DOM nesneleri veya diğer ana bilgisayar ortamlarındaki diğer nesneler gibi).

Yerleşik ve yerel nesnelerin ECMA-262'de tanımlanan miras şemasını uygulaması gerekirken, ana makine nesneleri bunu yapmaz. Bu nedenle, bir JavaScript ortamında değil tüm nesneler gerekir devralan Object.prototype . Örneğin, ActiveX nesneleri olarak uygulanan Internet Explorer'daki ana bilgisayar nesneleri, yerel nesneler olarak değerlendirilirse hatalar atar (bu nedenle try..catch , Microsoft XMLHttpRequest nesnelerini başlatmak için kullanılır ). Bazı DOM nesneleri (Internet Explorer'da tuhaf moddaki NodeLists gibi) Array yöntemlerine aktarılırsa hatalar atar, Internet Explorer 8 ve daha düşük sürümlerdeki DOM nesneleri ECMAScript benzeri bir devralma şemasına sahip değildir vb.

Bu nedenle, bir JavaScript ortamındaki tüm nesnelerin Object.prototype'dan miras aldığı varsayılmamalıdır.

yani JavaScript'teki her nesnenin prototip zinciri aracılığıyla hasOwnProperty işlevine erişimi vardır.

Bu, en azından Internet Explorer'daki tuhaflıklar modundaki (ve Internet Explorer 8 ve daha düşük sürümler her zaman) belirli ana bilgisayar nesneleri için doğru değildir.

Yukarıdakiler göz önüne alındığında, bir nesnenin neden kendi hasOwnProperty yöntemine sahip olabileceği ve bunun iyi bir fikir olup olmadığını test etmeden başka bir hasOwnProperty yöntemini çağırmanın tavsiye edilebilirliği üzerinde düşünmeye değer.

Kullanım nedeninin Object.prototype.hasOwnProperty.callbazı tarayıcılarda, ana bilgisayar nesnelerinin hasOwnProperty yöntemine sahip olmaması , call kullanmanın ve yerleşik yöntemin bir alternatif olması olduğundan şüpheleniyorum . Ancak, genel olarak bunu yapmak, yukarıda belirtilen nedenlerden dolayı iyi bir fikir gibi görünmüyor.

Ana bilgisayar nesneleri söz konusu olduğunda, in operatörü genel özellikleri test etmek için kullanılabilir, ör.

var o = document.getElementsByTagName('foo');

// false in most browsers, throws an error in Internet Explorer 6, and probably 7 and 8
o.hasOwnProperty('bar');

// false in all browsers
('bar' in o);

// false (in all browsers? Do some throw errors?)
Object.prototype.hasOwnProperty.call(o, 'bar');

Bir alternatif ( Internet Explorer 6 ve diğerlerinde test edilmiştir ):

function ownProp(o, prop) {

  if ('hasOwnProperty' in o) {
    return o.hasOwnProperty(prop);

  } else {
    return Object.prototype.hasOwnProperty.call(o, prop);
  }
}

Bu şekilde, yalnızca nesnenin sahip olmadığı (miras alınan veya başka türlü) yerleşik hasOwnProperty öğesini özel olarak çağırırsınız .

Bununla birlikte, bir nesnenin bir hasOwnPropertyyöntemi yoksa, nesnenin büyük olasılıkla bir kalıtım şemasına sahip olmaması ve tüm özelliklerin nesnede olması nedeniyle (bu sadece bir varsayım), örneğin in operatörünü kullanmak muhtemelen uygundur . in operatörü, özellikler için DOM nesnesi desteğini test etmenin yaygın (ve görünüşte başarılı) bir yoludur.


Teşekkürler. Object.prototype.hasOwnProperty.call (o, 'bar') FF 18.0'da çalışmıyor (en azından benim durumumda). Bu yüzden ('bar' in o) kullanmaya karar verdim ve yardımcı oldu.
Maksimum

@Max inbir hasOwnProperty()arama yapmıyor , aradığınız özelliğin prototip zincirinde olduğundan şüpheleniyorum.
alex

Bu, eslint.org/docs/rules/no-prototype-builtins'den ilginç bir örnektir : Örneğin, bir web sunucusunun bir istemciden JSON girdisini ayrıştırması ve hasOwnPropertydoğrudan ortaya çıkan nesneyi çağırması güvenli olmayacaktır , çünkü kötü niyetli bir istemci gibi bir JSON değeri gönderin {"hasOwnProperty": 1}ve sunucunun çökmesine neden olun.
naught101

Elbette, ancak endişeniz yalnızca veri kalitesi olsa bile, bu tür sorunları önlemek için istemci tarafından sağlanan JSON'u bir JSON şemasıyla test etmek veya doğrulamak akıllıca olacaktır. Ve sunucunun çökmesine neden olmamalıdır. :-)
RobG

8

JavaScript hasOwnProperty özellik adını korumaz

Bir nesnenin bu ada sahip bir özelliğe sahip olma olasılığı varsa, doğru sonuçları almak için harici bir hasOwnProperty kullanılması gerekir:

Daha iyi anlamak için aşağıdaki kod parçalarını kopyalayıp tarayıcı konsolunuza yapıştırabilirsiniz.

var foo = {
  hasOwnProperty: function() {
    return false;
  },
  bar: 'I belong to foo'
};

Her zaman yanlış döndürür

foo.hasOwnProperty('bar'); // false

Başka bir Nesnenin hasOwnProperty özelliğini kullanın ve bu set ile foo

({}).hasOwnProperty.call(foo, 'bar'); // true

Bu amaçla Nesne prototipinden hasOwnProperty özelliğini kullanmak da mümkündür.

Object.prototype.hasOwnProperty.call(foo, 'bar'); // true

1
Eğer yapıyoruz noktası zaten yapılmış kabul cevap o orada geçersiz kılma dışında hasOwnPropertygetiriler true.
Louis

1

İlk iki cevapta (tarihe göre) verilen bilgiler yerinde. Bununla birlikte, aşağıdakilerin kullanımı:

('propertyName' in obj)

birkaç kez bahsediliyor. hasOwnPropertyYalnızca özellik doğrudan test edilen nesne üzerinde yer alıyorsa , uygulamaların true döndürdüğüne dikkat edilmelidir .

inOperatör de prototip zinciri boyunca aşağı denetleyecek.

Bu hasOwnProperty, prototip özelliklerinin yanlış döndüreceği yere aktarıldığında örnek özelliklerinin true döndüreceği anlamına gelir .

Kullanılması inoperatörü hem örnek ve prototip özellikleri gerçek dönecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.