JavaScript dizi oluşturma - garip sözdizimi
Es-tartışma e-posta listesi: aşağıdaki kodu karşılaştım
Array.apply(null, { length: 5 }).map(Number.call, Number);
Bu üretir
[0, 1, 2, 3, 4]
Neden bu kodu sonucudur? Burada neler oluyor?
CEVAP
Anlayış bu "hack" anlayış gerektirir birkaç şey:
- Neden sadece
Array(5).map(...)
yapmıyoruz - Nasıl
Function.prototype.apply
bağımsız işler - Nasıl
Array
birden fazla bağımsız işler - Nasıl
Number
bağımsız değişken olarak işler - 32 ** nedir
Bu daha-daha-daha uzun olacak, bu yüzden javascript konularında ileri düzey, onlar değil. Baştan başlayacağız. Kemerlerinizi bağlayın!
1. Neden sadece Array(5).map
değil mi?
Bir dizi ne, gerçekten? Normal değerleri göster hangi tamsayı tuşları içeren nesne. Diğer özel özellikler, örneğin length
büyülü değişken vardır, ama sadece başka bir nesne gibi bir şey özünde, ** 35 normal bir harita değil. Hadi diziler ile biraz oynasak mı?
var arr = ['a', 'b', 'c'];
arr.hasOwnProperty(0); //true
arr[0]; //'a'
Object.keys(arr); //['0', '1', '2']
arr.length; //3, implies arr[3] === undefined
//we expand the array by 1 item
arr.length = 4;
arr[3]; //undefined
arr.hasOwnProperty(3); //false
Object.keys(arr); //['0', '1', '2']
Dizideki öğelerin sayısı arasındaki içsel fark var arr.length
key=>value
sayısı arr.length
daha farklı olabilir hangi dizi var eşleştirmeleri.
arr.length
ile dizi genişliyordeğilkey=>value
yeni haritalama, dizi tanımsız değerler olduğunu, bu yüzden değilbu anahtar yok. Ve var olmayan bir özellik erişmeye çalıştığınızda ne olur? undefined
olsun.
Şimdi kafamızı biraz Kaldır, ve arr.map
gibi işlevleri bu özellikler üzerinde yürümek yok neden bakın. arr[3]
sadece tanımsız ve anahtar varsa, bu dizi fonksiyonları sadece başka bir değer gibi geçer diye:
//just to remind you
arr; //['a', 'b', 'c', undefined];
arr.length; //4
arr[4] = 'e';
arr; //['a', 'b', 'c', undefined, 'e'];
arr.length; //5
Object.keys(arr); //['0', '1', '2', '4']
arr.map(function (item) { return item.toUpperCase() });
//["A", "B", "C", undefined, "E"]
Ben kasıtlı olarak daha fazla anahtar kendini asla var olduğunu kanıtlamak için bir yöntem çağrısı kullanılır: undefined.toUpperCase
Çağrılırken bir hata kaldırdı olurdu, ama olmadı. Kanıtlamak içinbu:
arr[5] = undefined;
arr; //["a", "b", "c", undefined, "e", undefined]
arr.hasOwnProperty(5); //true
arr.map(function (item) { return item.toUpperCase() });
//TypeError: Cannot call method 'toUpperCase' of undefined
Array(N)
işler Nasıl. ve şimdi benim noktaya mı geldik: Section 15.4.2.2 işlemini açıklar. Bir sürü saçma sapan şeyler umurumuzda bile değil, ama eğer sen yönetmek için okumak arasındaki çizgiler (veya sadece bana güven, ama yok), temelde aşağı kaynar bu
function Array(len) {
var ret = [];
ret.length = len;
return ret;
}
(len
geçerli bir gerçek spec işaretli olan) varsayımı altında faaliyet uınt32 ve değeri herhangi bir sayı)
Şimdi sen-ebilmek görmek neden yapıyor Array(5).map(...)
yaramaz - bilmiyoruz tanımlamak len
öğeleri dizisi, yok oluştur key => value
eşlemeleri, biz sadece alter length
özelliği.
En azından şimdi, ikinci büyülü bakayım:
2. Nasıl Function.prototype.apply
çalışır
apply
temel olarak bir dizi alır ve bir işlev çağrısı olarak göz önüne sermek ne argümanlar. Aşağıdaki hemen hemen aynı olduğu anlamına gelir:
function foo (a, b, c) {
return a b c;
}
foo(0, 1, 2); //3
foo.apply(null, [0, 1, 2]); //3
Şimdi, sadece arguments
özel değişken giriş yaparak apply
nasıl çalıştığını görmek işlemini kolaylaştırmak edebiliriz:
function log () {
console.log(arguments);
}
log.apply(null, ['mary', 'had', 'a', 'little', 'lamb']);
//["mary", "had", "a", "little", "lamb"]
//arguments is a pseudo-array itself, so we can use it as well
(function () {
log.apply(null, arguments);
})('mary', 'had', 'a', 'little', 'lamb');
//["mary", "had", "a", "little", "lamb"]
//a NodeList, like the one returned from DOM methods, is also a pseudo-array
log.apply(null, document.getElementsByTagName('script'));
//[script, script, script, script, script, script, script, script, script, script, script, script, script, script, script, script, script, script, script, script]
//carefully look at the following two
log.apply(null, Array(5));
//[undefined, undefined, undefined, undefined, undefined]
//note that the above are not undefined keys - but the value undefined itself!
log.apply(null, {length : 5});
//[undefined, undefined, undefined, undefined, undefined]
Kolay sondan ikinci örnekte: iddiamı kanıtlamak için
function ahaExclamationMark () {
console.log(arguments.length);
console.log(arguments.hasOwnProperty(0));
}
ahaExclamationMark.apply(null, Array(2)); //2, true
(Evet, kelime oyunu) kullanılır. key => value
eşleme apply
, geçtik dizideki bulunmayabilir, ama kesinlikle arguments
değişken var. Son örnek, işleri aynı sebepten dolayıdır: anahtarları verdiğimiz nesne yok, ama arguments
varlar.
Bu yüzden mi? Hadi Function.prototype.apply
tanımlandığı ** 117, bak. Çoğunlukla şeyler umurumda değil, ama burada ilginç olan kısmı:
4=başlangıç
- Len beni neden olsun [[]] değişkeni ile argArray iç yöntemi"". uzunluğu
Temelde anlamına gelir: argArray.length
. Spec o zaman gelirleri için basit bir for
döngü length
öğeler, yapma list
gelen değerleri (list
bazı iç voodoo, ama aslında bir dizi). Çok, çok gevşek kod: açısından
Function.prototype.apply = function (thisArg, argArray) {
var len = argArray.length,
argList = [];
for (var i = 0; i < len; i = 1) {
argList[i] = argArray[i];
}
//yeah...
superMagicalFunctionInvocation(this, thisArg, argList);
};
Bu durumda argArray
bir taklit etmeliyiz length
özelliği olan bir nesnedir. Ve şimdi değerleri tanımsızdır neden görebilirsiniz, ama anahtarlar yok, arguments
açık değil: key=>value
eşlemeleri oluşturmak.
Vay be, yani bu önceki bölümü daha kısa olabilirdi. Ama biz bitirmek, bu yüzden sabırlı olun zaman pasta olacak! Ancak, aşağıdaki bölümden sonra kısa olacak (söz) ifadesi diseksiyon başlayabiliriz. Unuttun galiba, soruyu nasıl aşağıdaki gibi çalışır:
Array.apply(null, { length: 5 }).map(Number.call, Number);
3. Nasıl Array
birden fazla bağımsız işler
Bu kadar! Gördük ne olur zaman geçirmek length
tartışma Array
ama ifadesinde, verdiğimiz birçok şey gibi argümanlar (bir dizinin 5 undefined
aslında). Section 15.4.2.1 bize ne anlatıyor. Son paragraf bizim için çok önemli ve ifadeligerçektengarip bir şekilde, ama aşağı kaynar:
function Array () {
var ret = [];
ret.length = arguments.length;
for (var i = 0; i < arguments.length; i = 1) {
ret[i] = arguments[i];
}
return ret;
}
Array(0, 1, 2); //[0, 1, 2]
Array.apply(null, [0, 1, 2]); //[0, 1, 2]
Array.apply(null, Array(2)); //[undefined, undefined]
Array.apply(null, {length:2}); //[undefined, undefined]
Tada! Birkaç tanımsız değerler dizisi var ve bu tanımsız değerler dizisi dönüyoruz.
İfadenin ilk bölümü
Son olarak, aşağıdaki deşifre edebiliriz:
Array.apply(null, { length: 5 })
Bir dizi 5 tanımsız değerleri içeren, tüm varlığı tuşları ile döndüren gördük.
Şimdi, bu ifadenin ikinci bölümü için:
[undefined, undefined, undefined, undefined, undefined].map(Number.call, Number)
Bu çok belirsiz kesmek güvenmek değil kolay olmayan, karmaşık parçası olacak.
4. Number
giriş yapıyorlar
Number(something)
(section 15.7.1) sayısı something
dönüştürür, ve hepsi bu. Bunu nasıl yaptığını biraz kıvrık, özellikle dizeleri durumda, ancak işlemi merak ediyorsanız section 9.3 olarak tanımlanır.
5. Function.prototype.call
oyunlar
call
apply
'In kardeşi, section 15.3.4.4 tanımlanmış. Bağımsız değişken bir dizi almak yerine, sadece alınan bağımsız değişkenleri alır ve onları öne geçirir.
İşler 91 ** birden fazla birlikte, garip 11 krank zincir ilginç:
function log () {
console.log(this, arguments);
}
log.call.call(log, {a:4}, {a:5});
//{a:4}, [{a:5}]
//^---^ ^-----^
// this arguments
Bu ne kavramak kadar oldukça işe layıktır. log.call
bir işlevi, fonksiyonu call
başka bir yöntem eşdeğerdir, ve gibi, kendisini call
bir yöntem de vardır:
log.call === log.call.call; //true
log.call === Function.call; //true
call
ne yapar? thisArg
ve argümanlar için bir demet bir kabul eder, ve onun ana işlevi çağırır. apply
(tekrar, çok gevşek kodu, işe yaramaz) o tanımlayabiliriz:
Function.prototype.call = function (thisArg) {
var args = arguments.slice(1); //I wish that'd work
return this.apply(thisArg, args);
};
Hadi bu iner nasıl takip:
log.call.call(log, {a:4}, {a:5});
this = log.call
thisArg = log
args = [{a:4}, {a:5}]
log.call.apply(log, [{a:4}, {a:5}])
log.call({a:4}, {a:5})
this = log
thisArg = {a:4}
args = [{a:5}]
log.apply({a:4}, [{a:5}])
Daha sonra bir bölümü ya da tüm .map
Henüz bitmedi. En dizi yöntemleri için bir fonksiyon kaynağı ne oluyor: bir bakalım
function log () {
console.log(this, arguments);
}
var arr = ['a', 'b', 'c'];
arr.forEach(log);
//window, ['a', 0, ['a', 'b', 'c']]
//window, ['b', 1, ['a', 'b', 'c']]
//window, ['c', 2, ['a', 'b', 'c']]
//^----^ ^-----------------------^
// this arguments
this
bir argüman kendimizi biz yok eğer doğru değilse, 105 ** varsayılan. Hangi argümanlar bizim geri verilir sırasını not edin, ve garip 11 yine tüm yol:
arr.forEach(log.call, log);
//'a', [0, ['a', 'b', 'c']]
//'b', [1, ['a', 'b', 'c']]
//'b', [2, ['a', 'b', 'c']]
// ^ ^
Hey hey...hadi biraz geçmişe gidelim bakalım. Burada neler oluyor? forEach
tanımlandığı section 15.4.4.18, görüyoruz, aşağıdaki oldukça fazla olur:
var callback = log.call,
thisArg = log;
for (var i = 0; i < arr.length; i = 1) {
callback.call(thisArg, arr[i], i, arr);
}
Yani, bu elde ederiz
log.call.call(log, arr[i], i, arr);
//After one `.call`, it cascades to:
log.call(arr[i], i, arr);
//Further cascading to:
log(i, arr);
Şimdi .map(Number.call, Number)
nasıl çalıştığını görebiliriz:
Number.call.call(Number, arr[i], i, arr);
Number.call(arr[i], i, arr);
Number(i, arr);
Bir sayı için i
, geçerli dizin, dönüşümü verir.
Sonuç olarak,
İfade
Array.apply(null, { length: 5 }).map(Number.call, Number);
Eserlerinde iki bölümden oluşur:
var arr = Array.apply(null, { length: 5 }); //1
arr.map(Number.call, Number); //2
İlk bölümü 5 tanımsız öğeleri bir dizi oluşturur. İkinci dizi gider ve endeks öğe Endeksi: bir dizi sonuç alır
[0, 1, 2, 3, 4]
Dinamik olarak JavaScript ilişkisel di...
JavaScript içinde bir dizi belirli bir...
-Her JavaScript bir dizi?...
dizi.(n) JavaScript içerir...
Nasıl JavaScript bir dizi boş?...