2017-12-31 177 views
2

Auf der einen Seite ist ein Mangel an einem Äquivalent Python 3 range ein Ärgernis in ES6. Auf der anderen Seite gibt es viele Problemumgehungen. Meine Frage ist, warum eine Workaround, die ich versuchte, tatsächlich funktioniert. Zur Veranschaulichung:Erstellen Sie eine Reihe von natürlichen Zahlen mit Spread-Syntax

[...Array(10).keys()]; 

Bei dem Grunde finde ich diese mysteriösen nicht offensichtlich ist, beachten Sie, dass Array(10).keys() ist zumindest scheinbar leer.

Ich weiß, dass dies verschwenderisch zwei Arrays erstellt, wie die meisten der gängigen Workarounds, und das (auf Kosten der Erstellung einer Generatorfunktion) mit einem Generator kann dies vermeiden. Beispiel:

[...(function*(){let i = 0; while(i<10) yield i++;})()]; 

Meine Frage ist nur darüber, warum die erste Problemumgehung das gewünschte Ergebnis erzeugt.

Edit:

aus den Antworten zu urteilen, glauben einige Leute, dass die Bewertung der Array(10) zur Bewertung von Array.apply(null,Array(10)) entspricht. Sie sind nicht. Zum Beispiel ist .hasOwnProperty(0)false für das erstere, aber true für das letztere. Ich bin jedoch offen dafür, dass sie überzeugt sind, dass sie in gewisser Weise die gleichen sind, die hier von Bedeutung sind, da mein Verständnis in einem entscheidenden Punkt eindeutig fehlt. Ich vermute, dass die Antwort ist, dass das Ergebnis der Iteration über die Schlüssel durch die length -Eigenschaft bestimmt wird, die beide teilen, anstatt die tatsächlichen Array-Indizes, die definiert wurden. Wenn ja, würde ich gerne wissen, dass dieses Verhalten normativ ist.

+0

https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Array/keys –

+0

'.keys() 'gibt einen * Iterator * zurück. Es ist kein Array, es ist nicht "scheinbar leer". – Bergi

+0

@Bergi Werfen Sie einen Blick darauf. Wie einige der Antworten scheinen Sie falsch zu verstehen, was von "Array (10)" erzeugt wird. (Oder vielleicht missverstehe ich deine Antwort.) – Alan

Antwort

3

Array#keys liefert einen ArrayIterator. Die Verteilungssyntax erschöpft dann diesen Iterator vollständig, indem er auf den nächsten Wert im Iterator zugreift, bis keine weiteren Werte vorhanden sind. Dann sammelt es alle Werte aus dem Iterator und verteilt sie in einem neuen Array.

Array(10) schafft eine array exotic object, die keine tatsächlichen integer indexierte haben Tasten, sondern nur eine length Eigenschaft - so wäre es ‚leer‘ aber Array(10).keys() nicht. Tatsache ist, dass Array#keysdoesn't depend on actual elements, just the length property verwendet wird. Die interne Operation CreateArrayIterator erstellt einen Schlüssel-Iterator aus einem Array, indem ein Iterator über den intrinsischen %ArrayIteratorPrototype% object erstellt wird. Wenn Sie %ArrayIteratorPrototype%.next() betrachten, sehen Sie, dass die Länge des Arrays verwendet wird. Für Array#keys wird der Index kontinuierlich erhöht, bis er die Länge des Arrays erreicht. Das ist, wie der Iterator erstellt wird, der Ihnen alle Schlüssel des Arrays ohne tatsächlich genannten ganzzahligen Schlüsseln an erster Stelle gibt.


Wenn Sie neugierig auf den abstrakten Schritten sind, siehe Section 12.2.5.2 ArrayAcculumation der ECMAScript-Sprachspezifikation, insbesondere die SpreadElement : ... AssignmentExpression Produktion, die den Prozess skizziert durch einen Iterator des Tretens, die in Verbindung mit gespreizter Syntax verwendet wird.

Die abstrakten Schritte zum Erfassen dieser Werte in einem neuen Array finden Sie unter Section 12.2.5.3 Evaluation. Speziell die ArrayLiteral : [ ElementList ] Produktion ist die Produktion [...Array.keys()] fällt unter. Der zuvor erwähnte ArrayAcculation-Prozess wird ausgeführt, wobei Aggregate durch den Iterator iterieren und diese in das neue Array setzen.

+0

Sie sagen "Schlüssel-Iterator von einem Array, indem Sie einen Iterator über das intrinsische'% ArrayIteratorPrototype% '- Objekt erstellen. Mit Blick auf'% ArrayIteratorPrototyp% .next() ', Sie werden sehen, dass die 'Länge' des Arrays verwendet wird." Das passt zu meinen Spekulationen und beantwortet meine Frage. Vielen Dank! – Alan

0

Array(10) erstellt ein Array der Länge 10, wobei jedes Element undefined ist.

Array(10).keys() gibt einen Iterator zurück, der über die Schlüssel des Arrays iteriert ... die Zahlen 0 bis .

Wenn die Spreadsyntax zum Definieren eines Array-Literals (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator) verwendet wird, iteriert es jeden angegebenen Iterator vollständig und fügt die zurückgegebenen Werte vom Iterator dem erstellten Array (in der Reihenfolge) hinzu.

+1

dies: "Jedes Element von denen ist undefined_" ist eigentlich nicht wahr. Es erstellt ein Array mit 10 ** leeren ** Slots. nicht "undefined" –

+0

Ich verstehe nicht die Unterscheidung, die Sie hier machen; Könntest du mehr sagen? Jede Position im Array ist eine gültige Referenz, die als Wert "undefined" zurückgibt. Es scheint, als wären sie im selben Status wie eine Variable, die deklariert, aber nicht zugewiesen wurde. –

+0

Zunächst ist es so in der [Docs] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#Parameters) "_empty Slots_". und für das 'undefined', das zurückgegeben wird, erhalten Sie das mit jeder Indexposition:' Array (10) [99] === undefiniert'. Nun, keine Position wirklich, der Bereich liegt zwischen 0 und 232-1 (inklusive) –

1

Array.prototype.keys gibt einen neuen Array-Iterator zurück.
Array(10) ist ein Array von 10 (leeren) Steckplätzen.

Wenn Sie die Schlüssel des Arrays verteilen, iterieren Sie darüber und erstellen ein neues Array. Aber diesmal sind die Elemente des neuen Arrays die Slots des ersten Arrays.

Sie können es mit for of Schleife sehen:

const arr = Array(10).keys(); 
 
for (let key of arr) { 
 
    console.log(key); 
 
}

By the way, können Sie Array.from verwenden, die eine map Funktion übernimmt, wie es das zweite Argument ist. so können Sie einfach den Index zurückkehren oder was auch immer Sie wollen:

const arr = Array.from(Array(10), (_, idx) => idx); 
 
console.log(arr);

bearbeiten
Als Followup auf Ihre editierten Frage nach dem Array(10) Ergebnis:
Die DOCS erwähnt:

Wenn das einzige Argument an die Array Const übergeben Ructor ist ein Integer zwischen 0 und 232-1 (inklusive), dies gibt ein neues JavaScript-Array mit seiner length -Eigenschaft auf diese Nummer (Hinweis: Dies bedeutet ein Array von ArrayLength leere Slots, nicht Slots mit tatsächlichen undefinierten Werte). Wenn das Argument eine andere Zahl ist, wird eine RangeError-Ausnahme ausgelöst.

So erhalten Sie tatsächlich:

  • Ein neues Array
  • Die Länge Eigenschaft mit der Nummer versehen an die Funktion

  • Sie erhalten n -slots aktualisiert

Nun wird .keys einen Iterator erstellen, der jeden Slot-Index als Wert zurückgibt.
zum Beispiel:

let it = Array(10).keys(); 

und Berufung:

it.next(); 

Wir kommen wieder:

{value: 0, done: false} 

es wieder aufrufen und

ergeben wieder
{value: n, done: false} 

bis Unti l wird es bis zum letzten Slot erhalten:

{value: 9, done: false} 

dann der nächste .next Anruf

{value: undefined, done: true} 

die wird Flagge zurückkehren wird, dass dies das Ende der Iterationen ist.

laufenden Beispiel:

const it = Array(10).keys(); 
 
console.log(it.next()); 
 
console.log(it.next()); 
 
console.log(it.next()); 
 
console.log(it.next()); 
 
console.log(it.next()); 
 
console.log(it.next()); 
 
console.log(it.next()); 
 
console.log(it.next()); 
 
console.log(it.next()); 
 
console.log(it.next()); 
 
console.log(it.next()); // done: true

Verwandte Themen