2014-10-22 15 views
6

Ben 2'yi Seç (source code) bakarak ve each2 yöntem prototipi bulunmuştur:Select2 each2 yöntemi - nasıl çalışır?

$.extend($.fn, { 
    each2 : function (c) { 
    var j = $([0]), i = -1, l = this.length; 
    while (
     ++i < l 
     && (j.context = j[0] = this[i]) 
     && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object 
    ); 
    return this; 
    } 
}); 

Sorum şu - bu yöntem nasıl çalıştığını? Demek istediğim - neden sadece koşulsuz bir döngü olsa, deyim parçası olmadan? Bu yöntemin akışını gerçekten anlamak isterim. Eğer bir koşul içine bir ifade koyduğunuzda

+0

Cevapları gözden geçirme şansınız oldu mu? Bu bir satır çözümü olmadığı için bir yorum bırakın ve eğer açık değilse, açıklık gerektirir. –

cevap

4

(örneğin: if (i), if (i == null), if (++i), if (i < 2)) onun bu true veya false olan 'işaretli' öncesi) ifadesi değerlendirilir olsun.

Canlı örnek: Biz var i = 0 var

; şimdi if (++i) console.log(i)'u ara. sentezleme 1 çok console.log(i) günlükleri 1 (bu JavaScript içinde gerçeği [ değil] olarak anlaşılır) geri ++i.

Şimdi diyelim ki var i = 0 ve if (++i && ++i) console.log(i). İlk ifadeler 1 değerini döndürür, böylece ikinci de 2 döndürür. Hem 1 ve 2gerçek olarak böylece console.log(i) günlükleri

Müthiş 2 davranılır. Yukarıdaki gibi aynı örnek üzerinde bir göz atalım ama if'dan önce var i = -1 başlıyoruz. Şimdi if (++i && ++i) console.log(i) diyoruz. İlk ++i, hata olan 0'u döndürür.

Devam etmek için, &&'un nasıl çalıştığını öğrenmek zorundasınız. Beni çabuk açıklayalım: Eğer yığın halinde exp1 && exp2 && exp3 ... && expX sonra exp2 sadece ( değerlendirdi) yürütülecektir zaman exp1 dönergerçeği (örneğin: true, 1, "some string"). exp3exp2truthy, yalnızca çalıştırılacaktır exp4exp3 gerçeği ve benzeri ... (biz expN çarpana kadar)

en geç f (++i && ++i) console.log(i) geri dönelim olduğunda. Yani sahtelik ilk ++i döner 0 olan böylece ikinci ++i yürütülür ve condition böylece console.log(i) yürütülmez false (tamamlandı Nasıl hiç incrementation yüzden i şimdi 0 eşittir) 'dir bütün değildir.

Şimdi aldığınız zaman while döngüsünün condition denetiminde aynı şekilde çalıştığını söyleyebilirim. Örneğin, var = -2 ve while (++i), ++ihata (bu 0) değerini döndürene kadar yürütülür. while (++1) tam olarak 2 kez yürütülür.

TL;

Peki bu nasıl çalışır?

while (
     ++i < l 
     && (j.context = j[0] = this[i]) 
     && c.call(j[0], i, j) !== false 
    ); 

Açıklamaya iyi yolu, onu yeniden yazmak olduğunu düşünüyorum (:

while (++i < l) { 
     if (!(j.context = j[0] = this[i])) break; 
     if (!(c.call(j[0], i, j) !== false)) break; 
    } 

veya hiç az büyülü:

var i = 0; 
    while (i < l) { 
     if (!(j.context = j[0] = this[i])) break; 
     if (!(c.call(j[0], i, j) !== false)) break; 
     i++; 
    } 
+0

Ancak, while döngüsünün yukarıdaki örneğinde tam olarak ne işlenecek? Açıklama yok, sadece durum. Bu benim sorunum olan kısım. Döngünümün 2 kez yürütüldüğünü söyleyeyim - hangi kısım idam ediliyor? –

+0

var. İnanıyorum ki (j.context = j [0] = bu [i]) 'bu algoritmanın özüdür. Ayrıca c.call (j [0], i, j) 'burada 'şey' yapabilirdi. –

+0

Bunu böyle yazabildiğinizden emin misiniz? Bu tür bir dönüşüm için bir çeşit kaynak sağlayabilir misiniz? –

3
kodun amacı

yeni bir fonksiyon eklemek için, .each ile benzer şekilde çalışan jQuery nesnesine Bu .each2 işlevinin kullanımı, jQuery nesnesi üzerinde çalışan .each ile aynıdır. t, 2 arg (dizin ve değer) ile geri aramak ve jQuery nesnesini döndürmek için bir işlev alır.

döngü sırasında gizemli,

while (
    ++i < l 
    && (j.context = j[0] = this[i]) 
    && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object 
); 
    return this; 
} 

Gözlemler:

  1. 3 koşulların true
  2. İlk Durumuna değerlendirir "yalnızca" Devam: ++i < l, basit bir yinelemeyi olarak değerlendirilirse i değeri seçilen öğelerin sayısından az olana kadar doğrudur.
  3. İkinci Durumu [i çünkü bir sonraki hat ++i ve i kullanım, -1 için başlatılır, daha sonra referanslarda indeksi olarak kullanılmaktadır]: Aslında, bir başlatma + boş/tanımlanmamış bir kontroldür. Durum geçerli tüm değerler için doğru olarak değerlendirilir ve geçersiz bir bağlam olduğunda başarısız olur.
  4. Üçüncü durum: Bu koşulun amacı, geri arama işlevi yanlış olduğunda dönüşü kesmenize izin verir. .each ile aynı şekilde, işlev içinde return false yineleme işlemini bozar.
+0

İki şey hariç doğru sayılırsınız. 'her2' diziler üzerinde çalışır (veya üzerinde yinelenebilir bir uzunluk ile herhangi bir şey. Ve senin 1 gözlem yanlıştır, * sadece * her 3 koşul doğruysa. – RustyToms

+0

@RustyToms Teşekkürler, ama jQuery nesnenin uzunluğu vardır ve Ancak iterated ancak .each2'nin bunun için kastettiğini söyleyemem. '.each2' özellikle bu eklenti için tasarlandı, dolayısıyla kullanım sadece bir yardımcı fonksiyon olarak çalışacak şekilde sınırlı olabilir ve benim 1. gözlemim basitçe Durumun herhangi birinin yanlış olarak değerlendirilmediği sürece süre devam ederse, "olana kadar" ve "yalnızca eğer" bu bağlamda farklı olduğundan emin değilsiniz. –

+0

"her2" nin jQuery nesneleriyle sınırlı olmadığını, ancak evet, sanırım çünkü herbir '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' 'jQuery nesnesi doğrudur, jQuery nesnesine özgüdür.İlk gözleminizi doğru olarak düşündüğünüzü düşünüyorum ama dilbilgisi yanlıştır. Aksine, "tüm 3 kondisyona kadar devam ediyor" derken ns doğru olarak değerlendirir "eğer tüm 3 koşul doğru olarak değerlendirilirse hemen duracak demektir. Ama tam tersi doğrudur, sadece 3'ün tümü doğru olduğu sürece devam edecektir. Yani "if" ile "olana kadar" yerine, o zaman cevabınız doğru. – RustyToms

1

OP tarafından belirtildiği gibi, while koşulundan sonra hiçbir ifade yoktur. While döngüsünden sonra noktalı virgülü not alın, return this sadece while döngüsü tamamlandıktan sonra çalıştırılır ve bu üç ifadeden herhangi biri false olarak değerlendirilir. Eğer bilmek istediğiniz her şey, while döngüsünün nasıl çalıştığıysa, Filip Bartuzi'nin cevabı muhtemelen en eksiksiz. each2 yönteminin ne yaptığını daha geniş bir yanıt vermeye çalışacağım.

olarak sadece jQuery's #each veya Array.prototype.forEach veya Underscore's #each veya Select2 en kullanımlar için özel olarak tasarlanmıştır lodash's #forEach daha verimli versiyonu, docs kaydetti. Bir jQuery nesnesine sarılmış herhangi bir dizi veya başka yinelenebilir üzerinde yineleme yapmak için kullanılır. Bu yüzden diziler dizileri ve jQuery koleksiyonları için kullanılır.

Çalışma şekli, kapsam() çağrısının yapıldığı dizidir. Argüman olarak bir işlev verilir. Bu, daha önce bahsettiğim diğer each yöntemlerinin nasıl adlandırıldığıdır. Dizideki her öğe için each2'a verilen işlev bir kez çağrılır. While döngüsü, dizideki her öğe üzerinde yinelemenin hacky yoludur ve işlevi çağırır, öğeyi bağlam olarak ayarlar ve dizini diziye geçirir ve öğeyi birinci ve ikinci argümanlar olarak jQuery nesnesi olarak geçirir.while döngü koşulundaki her ifade doğru olup olmadığını belirlemek için değerlendirilmeli ve bu değer değerleri gerçekten değişkenlere atamak için kullanılır ve i değerini artırır. c.call(j[0], i, j) !== false bölümü, işlevin false döndürerek döngüyü erken sonlandırmasına izin verir. Eğer işlev false döndürürse, while döngüsü duracaktır, aksi halde il'dan büyük olana kadar devam edecektir, yani dizideki her öğe kullanılmış demektir. Daha sonra this döndürülmesi, .each2'dan sonra diziye başka bir yöntemin zincirlenmesine olanak tanır.

Temelde while döngü için yazılabilirdi:

var j = $([0]), i = 0, l = this.length, continue = true; 
while (i < l) { 
    i++; 
    j.context = j[0] = this[i]; 
    continue = c.call(j[0], i, j); 
    if (!continue) { 
    break; 
    } 
} 

ama bu tarayıcı tarafından hem optimize edilemez neden bazı performans nedenleri muhtemelen vardır.

Normal each yöntemlerinden daha hassastır. Örneğin, dizideki bir öğenin 0 gibi bir falsey değerine sahip olması durumunda, (j.context = j[0] = this[i]) döngü olacaktır, bu da döngünün sonlandırılmasına neden olur. Ancak, yalnızca select2 kodunun özel durumlarda kullanılır, bunun olmaması gerekir.

Birkaç örnek üzerinden geçelim.

function syncCssClasses(dest, src, adapter) { 
    var classes, replacements = [], adapted; 

    classes = $.trim(dest.attr("class")); 

    if (classes) { 
     classes = '' + classes; // for IE which returns object 

     $(classes.split(/\s+/)).each2(function() { 
      if (this.indexOf("select2-") === 0) { 
       replacements.push(this); 
      } 
     }); 
    } 
    ... 

^

Bu kod dest DOM öğesinden sınıfları oluyor. Sınıflar bir dizi diziye bölünür (dize boşluk karakterleri üzerine bölünür, bu \s+ düzenli ifade), her sınıf adı dizideki bir öğedir. Burada özel bir jQuery çalışması gerekmez, bu nedenle each2 tarafından çağrılan fonksiyonun sağlandığı 2 argüman kullanılmaz. Eğer sınıf 'select2-' ile başlarsa, sınıf replacements adında bir diziye eklenir. 'Select2-' sınıfları kopyalanıyor, oldukça basit.

group.children=[]; 
$(datum.children).each2(function(i, childDatum) { process(childDatum, group.children); }); 

^kısalık için ben bu yöntemin kalanını dahil değil ama process yöntemin bir parçasıdır. Bu durumda,, bir düğümde ve tüm bu çocuklar için tekrarlı olarak process kullanılıyor. $(datum.children) jQuery seçimi, her 'child' (childDatum olarak adlandırılır) sırayla işlenir ve çocuklar aynı işlemden geçirilir. group.children dizisi bir koleksiyon olarak kullanılacaktır, her childDatum için bu diziye eklenenler kullanılabilir olacaktır, böylece each2 çalıştırıldıktan sonra tüm çocukların, torunların vb. Işlemleri sırasında eklenen her şeyi tutacaktır.