Bir JavaScript dosyamda JSLint kullandım . Hatayı attı:
for( ind in evtListeners ) {
41. satır 9'daki sorun: Prototipten istenmeyen özellikleri filtrelemek için bir for in öğesinin bir if ifadesine sarılması gerekir.
Ne anlama geliyor?
Bir JavaScript dosyamda JSLint kullandım . Hatayı attı:
for( ind in evtListeners ) {
41. satır 9'daki sorun: Prototipten istenmeyen özellikleri filtrelemek için bir for in öğesinin bir if ifadesine sarılması gerekir.
Ne anlama geliyor?
Yanıtlar:
Her şeyden önce, bir dizi üzerinde numaralandırmak için asla bir for in
döngü kullanmayın . Asla. Eskiyi kullan for(var i = 0; i<arr.length; i++)
.
Bunun sebebi şudur: JavaScript'teki her nesnenin adlı özel bir alanı vardır prototype
. Bu alana eklediğiniz her şeye, o türdeki her nesnede erişilebilir olacak. Tüm dizilerin filter_0
sıfırları filtreleyecek yeni ve harika bir fonksiyona sahip olmasını istediğinizi varsayalım .
Array.prototype.filter_0 = function() {
var res = [];
for (var i = 0; i < this.length; i++) {
if (this[i] != 0) {
res.push(this[i]);
}
}
return res;
};
console.log([0, 5, 0, 3, 0, 1, 0].filter_0());
//prints [5,3,1]
Bu, nesneleri genişletmenin ve yeni yöntemler eklemenin standart bir yoludur. Birçok kütüphane bunu yapıyor. Ancak, for in
şimdi nasıl çalıştığına bakalım :
var listeners = ["a", "b", "c"];
for (o in listeners) {
console.log(o);
}
//prints:
// 0
// 1
// 2
// filter_0
Görüyor musun? Aniden filter_0'ın başka bir dizi indeksi olduğunu düşünüyor. Tabii ki, bu gerçekten bir sayısal dizin for in
değil, sadece sayısal dizinler değil, nesne alanları üzerinden numaralandırılır. Şimdi her sayısal indeks üzerinden numaralandırıyoruz ve filter_0
. Ancak filter_0
belirli bir dizi nesnesinin alanı değil, her dizi nesnesinin şimdi bu özelliği vardır.
Neyse ki, tüm nesnelerin hasOwnProperty
bu alanın gerçekten nesnenin kendisine mi yoksa prototip zincirinden miras alındığını ve böylece bu türdeki tüm nesnelere ait olup olmadığını kontrol eden bir yöntemi vardır.
for (o in listeners) {
if (listeners.hasOwnProperty(o)) {
console.log(o);
}
}
//prints:
// 0
// 1
// 2
Not bu kod çalışır halde diziler için beklendiği gibi, bunu kullanmalısınız asla asla , kullanım for in
ve for each in
diziler için. for in
Dizi dizinleri veya değerleri değil, bir nesnenin alanlarını numaralandırdığını unutmayın .
var listeners = ["a", "b", "c"];
listeners.happy = "Happy debugging";
for (o in listeners) {
if (listeners.hasOwnProperty(o)) {
console.log(o);
}
}
//prints:
// 0
// 1
// 2
// happy
for in
Diziler üzerinde yineleme yapmak için kullanmamalısınız , çünkü dil for in
bir dizi üzerinde numaralandırılacak sıraya göre sıralanmaz. Sayısal sırada olmayabilir. Ayrıca, `for (i = 0; i <array.length; i ++) stil yapısını kullanırsanız, yalnızca sayısal dizinleri sırayla yinelediğinizden ve alfasayısal özellik olmadığından emin olabilirsiniz .
for-in
döngülerden korkutmak yerine (bu arada harika), onları nasıl çalıştıklarını (bu cevapta düzgün bir şekilde yapılıyor) eğitmeli Object.defineProperty()
ve prototiplerini hiçbir şey kırmadan güvenli bir şekilde genişletebilmeleri için onları eğitmeliyiz . Bu arada, uzayan yerli nesnelerin prototipler gerektiğini değil olmadan yapılabilir Object.defineProperty
.
Jslint'in yazarı Douglas Crockford, bu konu hakkında birçok kez yazdı (ve konuştu). Web sitesinin bu sayfasında aşağıdakileri kapsayan bir bölüm var :
Açıklama için
İfade sınıfları için A aşağıdaki biçime sahip olmalıdır:
for (initialization; condition; update) { statements } for (variable in object) { if (filter) { statements } }
İlk form, dizilerle ve önceden belirlenmiş sayıda yinelemenin döngülerinde kullanılmalıdır.
İkinci form nesnelerle birlikte kullanılmalıdır. Nesnenin prototipine eklenen üyelerin numaralandırmaya dahil edileceğini unutmayın. Nesnenin gerçek üyelerini ayırt etmek için hasOwnProperty yöntemini kullanarak defalarca programlamak akıllıca olacaktır:
for (variable in object) { if (object.hasOwnProperty(variable)) { statements } }
Crockford'un YUI tiyatrosunda bunun hakkında konuştuğu bir video dizisi var. Crockford'un javascript hakkında videolar / konuşmalar dizisi, javascript hakkında biraz ciddi olup olmadığınızı görmek için bir zorunluluktur.
Vava'nın cevabı işaretin üstünde. JQuery kullanıyorsanız, $.each()
işlev bununla ilgilenir, bu nedenle kullanımı daha güvenlidir.
$.each(evtListeners, function(index, elem) {
// your code
});
$.each
(veya underscore.js _.each
) kullanmanızı tavsiye etmem for
. jsperf, çalıştırılmaya değer birkaç göz açıcı karşılaştırma testine sahiptir.
@all - JavaScript'teki her şey bir nesnedir (), bu nedenle "bunu yalnızca nesnelerde kullanın" gibi ifadeler biraz yanıltıcıdır. Ayrıca, JavaScript = 1 == "1" doğru olacak şekilde güçlü bir şekilde yazılmamıştır (1 === "1" olmamasına rağmen, Crockford bu konuda büyüktür). JS'deki progromatik diziler söz konusu olduğunda, tanımda yazım önemlidir.
@Brenton - Bir terminoloji diktatörü olmaya gerek yok; "ilişkilendirilebilir dizi", "sözlük", "karma", "nesne", bu programlama kavramlarının tümü JS'deki tek bir yapı için geçerlidir. Ad (anahtar, dizin) değer çiftleridir, burada değer başka bir nesne olabilir (dizeler de nesnedir)
Yani,
new Array()
aynı[]
new Object()
kabaca benzer {}
var myarray = [];
Tüm dizinlerin (aka anahtarlar) tam sayı olması gereken kısıtlamaya sahip bir dizi olan bir yapı oluşturur. Ayrıca .push () aracılığıyla yeni dizinlerin otomatik olarak atanmasına izin verir.
var myarray = ["one","two","three"];
Gerçekten en iyi şekilde ele alınır for(initialization;condition;update){
Ama ne hakkında:
var myarray = [];
myarray[100] = "foo";
myarray.push("bar");
Bunu dene:
var myarray = [], i;
myarray[100] = "foo";
myarray.push("bar");
myarray[150] = "baz";
myarray.push("qux");
alert(myarray.length);
for(i in myarray){
if(myarray.hasOwnProperty(i)){
alert(i+" : "+myarray[i]);
}
}
Belki bir dizinin en iyi kullanımı değil, sadece şeylerin her zaman net olmadığı bir örnek.
Anahtarlarınızı biliyorsanız ve kesinlikle tam sayı değilse, yapı gibi tek diziniz nesnedir.
var i, myarray= {
"first":"john",
"last":"doe",
100:"foo",
150:"baz"
};
for(i in myarray){
if(myarray.hasOwnProperty(i)){
alert(i+" : "+myarray[i]);
}
}
Elbette söylemesi biraz aşırı
... bir dizi üzerinde numaralandırmak için hiçbir zaman for in döngüsü kullanmayın. Asla. Şunun için iyi eskiyi kullanın (var i = 0; i <arr.length; i ++)
?
Douglas Crockford ekstresindeki bölümü vurgulamaya değer
... İkinci form nesnelerle kullanılmalı ...
Anahtarlar yerine sayısal endeksli ait adlandırılır ilişkilendirilebilir bir dizi (aka hashtable / sözlük) gerekiyorsa, örneğin bir nesne olarak bu uygulamaya sahip olacaktır var myAssocArray = {key1: "value1", key2: "value2"...};
.
Bu durumda myAssocArray.length
null ortaya çıkar (çünkü bu nesnenin 'length' özelliği yoktur) ve i < myAssocArray.length
sizi çok ileri götürmezsiniz. Daha fazla kolaylık sağlamanın yanı sıra, dizi anahtarları yararlı özellikler (yani bir dizi üyesinin ID özelliği veya adı) olabileceğinden, ilişkilendirilebilir dizilerin birçok durumda performans avantajları sunmasını beklerim, yani uzun bir yineleme yapmak zorunda değilsiniz dizi, peşinde olduğunuz dizi girişini bulmak için if ifadelerini tekrar tekrar değerlendirir.
Her neyse, JSLint hata mesajlarının açıklaması için de teşekkürler, sayısız ilişkilendirilebilir dizilerle entegrasyon yaparken şimdi 'isOwnProperty' kontrolünü kullanacağım!
length
özelliği olmadığı doğrudur , ancak başka bir şekilde yapabilirsiniz:var myArr = []; myArr['key1'] = 'hello'; myArr['key2'] = 'world';
var myArr = []
, var myArr = {}
PHP'de aynı şey olmalı , ancak JS'de olmamalıdır.
Bu, evtListeners öğelerinin özelliklerini hasOwnProperty yöntemiyle filtrelemeniz gerektiği anlamına gelir .
Sadece in / for / $ için konuya eklemek için, her biri $ .each vs for kullanmak için bir jsperf test örneği ekledim: http://jsperf.com/each-vs-for-in/2
Farklı tarayıcılar / sürümler farklı şekilde işlemektedir, ancak $ .each ve in için olduğu gibi performans açısından en ucuz seçenekler.
İlişkilendirilebilir bir dizi / nesne üzerinden yineleme yapmak, sonra ne yaptığınızı bilmek ve diğer her şeyi göz ardı etmek için kullanıyorsanız, jQuery kullanıyorsanız $ .each veya yalnızca in için (ve sonra bir mola; bir kez son öğe olması gerektiğini bildiğiniz şeye ulaştı)
İçindeki her anahtar çifti ile bir şeyler gerçekleştirmek için bir dizi üzerinden yineliyorsanız, jQuery kullanmadığınız takdirde hasOwnProperty yöntemini kullanmanız ve jQuery kullanıyorsanız DO $ .each kullanmanız gerekir.
İlişkisel for(i=0;i<o.length;i++)
bir diziye ihtiyacınız yoksa her zaman kullanın ... lol chrome, bir in veya$.each
if (evtListeners.hasOwnProperty(ind))
işlemeyi yalnızca kendi (kalıtsal olmayan) özelliklerle sınırlamak için sarılır . Yine de, bazı durumlarda, miras alınanlar da dahil olmak üzere tüm mülkleri yinelemek istersiniz. Bu durumda, JSLint, gerçekten hangi özellikleri istediğinize karar vermek için döngü gövdesini bir if ifadesine sarmaya zorlar. Bu işe yarayacak ve JSlint'i mutlu edecek:if (evtListeners[ind] !== undefined)