2016-06-17 14 views
2

Der folgende Code:Mapping Array in Javascript mit fortlaufenden Nummern

let myArray = Array.apply(null, {length: 10}).map(Number.call, Number); 

erstellt folgende Array:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

Ich verstehe einfach nicht, warum. Ich kann nichts im Internet finden, das dieses Verhalten erklärt. Weiß jemand, warum das so funktioniert? Vielleicht ein Link zu einer Dokumentation?

+0

Ist das klarer? 'Array.apply (null, {Länge: 10}). Map (Function.prototype.call, Number)' – elclanrs

+0

Bevor Sie den Code verstehen, verstehen Sie bitte das Konzept der .map-Funktion in Javascript. Gehen Sie durch diesen Link http://www.w3schools.com/jsref/jsref_map.asp –

Antwort

5
Array.apply(null, {length: 10}) 

erstellt ein Array der Länge 10 mit allen Elementen undefined.

.map(Number.call, Number) 

Number.call wird mit den Argumenten für jedes Element aufrufen (element, index, array) und this zu Number Einstellung. Das erste zu rufende Argument wird als this (hier nicht relevant) genommen, und alle anderen Argumente werden so wie sie sind übergeben, wobei der erste der Index ist. Und Number konvertiert nun sein erstes Argument, index, in eine Zahl (hier: gibt den Index zurück, da es eine Zahl ist), und das ist es, was Map in ihr Rückgabe-Array schreibt.

+0

Macht so viel Sinn, vielen Dank! Auch das fand ich sehr hilfreich: [array.map()] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) und [dies] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) –

+0

Danke für die Erklärung. Scheint wie eine komplizierte Art, dies zu tun. In Python wäre das 'myArray = range (0,10)' – bhspencer

10

Lassen Sie uns den Ausdruck in zwei Teile zerlegen:

1) Lassen Sie uns den ersten Ausdruck diskutieren:

Array.apply(null, {length: 10}) 

In JavaScript, um die Array Konstruktor einen Parameter nehmen können ein Array mit einer bestimmten Länge zu erstellen, wie :

Array(10) // makes an array of length 10 

Dieses Array ist ein Sparse-Array (ein Array, das Indizes ohne Elemente enthält). Sie können sich vorstellen, wir folgende Array generiert:

[,,,,,,,,] // Array with 10 indexes, but no elements 

Sie können in JavaScript als Objekt eines Arrays denken, die eine length Eigenschaft und nummeriert Indizes hat. Zum Beispiel ist die folgende eine gültige Darstellung eines Arrays:

var arr = {length: 3, 0: 1, 1: 2, 2: 3} // this represents the array [1, 2, 3] 

In JavaScript wir dieses Objekt aufrufen, um eine „Array-ähnliches Objekt“.Sie können dieses Objekt mit einer regelmäßigen for Schleife durchlaufen:

for (var i=0; i<arr.length; i++) { 
    console.log(arr[i]) // logs 1 .. 2 .. 3 
} 

Aber diese Aufgabe ist nicht eine Instanz des Array Konstruktor:

arr instanceof Array // false 

Glücklicherweise jedes Array-artigen Objekt kann in ein Array umgewandelt werden :

Array.prototype.slice.call({length: 3, 0: 1, 1: 2, 2: 3}) // [1, 2, 3] 

Alle dieses Verhalten zu ermöglichen, sind Array Methoden absichtlich generisch, so können Sie mit forEach für Blutzuckerwer leicht Schleife le:

Array.prototype.forEach.call({length: 3, 0: 1, 1: 2, 2: 3}, function(x) { 
    console.log(x) 
}) 

Nun zurück zum ersten Ausdruck:

Array.apply(null, {length: 10}) 

den obigen Ausdruck Dekomposition zu wissen, über Array-ähnliche Objekte, das können wir sehen, ist äquivalent zu:

Array(undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); 

Mit anderen Worten, wir erstellen ein Array von 10 Elementen mit einem Wert von undefined (beachten Sie, dass es nicht mehr spärlich ist)

2) in den zweiten Ausdruck Going:

.map(Number.call, Number); 

Das erste Argument ist eine Callback-Funktion auf jedes Element in dem Array, das zweite Argument ist der this Wert innerhalb des Callback anzuwenden.

Lassen Sie uns diesen Ausdruck zerlegen. Zunächst können wir die Callback-Funktion als eine anonyme Funktion schreiben:

Array.apply(null, {length: 10}).map(function() { 
    return Number.call.apply(this, arguments) 
}, Number) 

Dann erkennen wir, dass Number.call ist eine Abkürzung für Function.prototype.call:

Array.apply(null, {length: 10}).map(function() { 
    return Function.prototype.call.apply(this, arguments) 
}, Number) 

Als nächstes Inline wir den this Wert:

Array.apply(null, {length: 10}).map(function() { 
    return Function.prototype.call.apply(Number, arguments) 
}) 

Und schließlich zerlegen wir die Anwendung der Funktion:

Array.apply(null, {length: 10}).map(function() { 
    return Number.call(arguments[0], arguments[1], arguments[2]) // map provides 3 arguments 
}) 

Wie Sie sehen können, ist das erste Argument, das das Element ist, das undefined ist der this Wert des Anrufs Number, die wir verwerfen zu sagen ist. Das zweite Argument ist der Index, der Wert, der uns wichtig ist, und das dritte Argument wird nicht benötigt, da Number nur ein Argument benötigt, also wird dieses auch verworfen.

In diesem Fall ist die Funktion Number als indentity Funktion verwendet:

function id(x) { 
    return x 
} 

Es ist lediglich eine Funktion von einem Argument, das dieses Argument zurückgibt. Das ist alles, was uns interessiert.Da index ist bereits eine Zahl, die wir bekommen, dass:

Number(index) === id(index) 

Hoffnung, dass weiteres Verständnis hilft.

Edit: auf den Grund zu erweitern, warum Array(10) nicht mit Iterationsverfahren arbeiten wie map gegen Array.apply(null, {length: 10}) wir am implementation of map (navigieren Sie zu dem „Polyfill“ Überschrift) zu suchen.

Der Grund ist, weil, wie ich zuvor hingewiesen habe, Array(10) ist ein Sparse-Array, es hat keine Werte drin, nur eine Länge. Mit Blick auf die Umsetzung können wir sehen, was passiert:

// 8. Repeat, while k < len 
while (k < len) { 

    var kValue, mappedValue; 

    // a. Let Pk be ToString(k). 
    // This is implicit for LHS operands of the in operator 
    // b. Let kPresent be the result of calling the HasProperty internal 
    // method of O with argument Pk. 
    // This step can be combined with c 
    // c. If kPresent is true, then 
    if (k in O) { 

    // i. Let kValue be the result of calling the Get internal 
    // method of O with argument Pk. 
    kValue = O[k]; 

Sie können die in Operator prüft, ob Existenz in k in O sehen, dass ersten und der Wert nicht vorhanden ist; es ist nicht undefined, es ist einfach nicht vorhanden. Dies ist nicht dasselbe wie nur den Zugriff auf Eigenschaften wie O[k] auszuführen, wo es einen Wert von undefined ergibt, wenn die Eigenschaft nicht existiert.

var o = {} 

'p' in o // false 
o.p // undefined 
+1

Vielen Dank - Das war wirklich eine sehr nette Lektüre. Ich habe bereits eine Antwort gegeben. Wenn diese Antwort aufgewertet wird, werde ich die Antwort auf diese ändern. Meine Güte, danke für deine Mühe! –

+1

Gut gelesen, aber es erklärt nicht den kniffligen Punkt. Der zweite Teil ist nichts als Täuschung. Es kann einfach wie '.map ((e, i) => i)' durchgeführt werden. Der interessante Teil ist jedoch, wie map auf einem Array voller undefinierter Elemente woks. Normalerweise funktioniert 'Array (10) .map ((e, i) => i)' nicht. Aber in diesem Fall ist das Array, das man mit 'Array.apply (null, {length: 10}) erhalten hat, anscheinend nicht das gleiche wie das Array Array (10) und die Karte arbeitet mit undefinierten Elementen. Wie ist das möglich..? – Redu

+1

@Redu weil 'Array (10)' Ihnen ein Sparse-Array gibt (und die Karte funktioniert nicht), aber 'Array.apply (null, {length: 10})' gibt das Array mit einem nicht definierten Wert zurück (und map arbeitet mit it) – Daviz