Bereich in JavaScript erstellen - seltsame Syntax

129

Ich habe den folgenden Code in der Mailingliste von es-execute gefunden:

Array.apply(null, { length: 5 }).map(Number.call, Number);

Dies erzeugt

[0, 1, 2, 3, 4]

Warum ist das das Ergebnis des Codes? Was passiert hier?

Benjamin Gruenbaum
quelle
2
IMO Array.apply(null, Array(30)).map(Number.call, Number)ist einfacher zu lesen, da nicht vorgetäuscht wird, ein einfaches Objekt sei ein Array.
Fncomp
10
@fncomp Bitte verwenden Sie entweder nicht tatsächlich eine Reihe erstellen. Es ist nicht nur langsamer als der einfache Ansatz - es ist bei weitem nicht so einfach zu verstehen. Es ist schwer, die Syntax (nun ja, wirklich die API und nicht die Syntax) hier zu verstehen, was dies zu einer interessanten Frage macht, aber zu einem schrecklichen Produktionscode IMO.
Benjamin Gruenbaum
Ja, ich schlage nicht vor, dass jemand es verwendet, dachte aber, es sei im Vergleich zur Objektliteralversion immer noch leichter zu lesen.
Fncomp
1
Ich bin mir nicht sicher, warum jemand das tun möchte. Die Zeit, die benötigt wird, um das Array auf diese Weise zu erstellen, hätte etwas weniger sexy, aber viel schneller erfolgen können: jsperf.com/basic-vs-extreme
Eric Hodonsky

Antworten:

263

Um diesen "Hack" zu verstehen, müssen Sie verschiedene Dinge verstehen:

  1. Warum wir es nicht einfach tun Array(5).map(...)
  2. Wie geht man Function.prototype.applymit Argumenten um?
  3. Wie geht man Arraymit mehreren Argumenten um?
  4. Wie die NumberFunktion mit Argumenten umgeht
  5. Was Function.prototype.callmacht

Es handelt sich um ziemlich fortgeschrittene Themen in Javascript, daher wird dies mehr als lang sein. Wir werden von oben beginnen. Anschnallen!

1. Warum nicht einfach Array(5).map?

Was ist eigentlich ein Array? Ein reguläres Objekt, das Ganzzahlschlüssel enthält, die Werten zugeordnet sind. Es hat andere Besonderheiten, zum Beispiel die magische lengthVariable, aber im Kern ist es eine reguläre key => valueKarte, genau wie jedes andere Objekt. Lass uns ein bisschen mit Arrays spielen, sollen wir?

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']

Wir kommen zu dem inhärenten Unterschied zwischen der Anzahl der Elemente im Array arr.lengthund der Anzahl der key=>valueZuordnungen im Array, die sich von unterscheiden können arr.length.

Die Erweiterung des Arrays über arr.length keine keine neuen erstellen key=>valueZuordnungen, so ist es nicht , dass das Array undefinierte Werte hat, es verfügt nicht über diese Tasten . Und was passiert, wenn Sie versuchen, auf eine nicht vorhandene Eigenschaft zuzugreifen? Du verstehst undefined.

Jetzt können wir unsere Köpfe ein wenig heben und sehen, warum Funktionen wie arr.mapdiese Eigenschaften nicht überschreiten. Wenn arr[3]nur undefiniert wäre und der Schlüssel vorhanden wäre, würden alle diese Array-Funktionen wie jeder andere Wert darüber hinweggehen:

//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"]

Ich habe absichtlich einen Methodenaufruf verwendet, um weiter zu beweisen, dass der Schlüssel selbst nie vorhanden war: Das Aufrufen undefined.toUpperCasehätte einen Fehler ausgelöst, aber dies war nicht der Fall. Um zu beweisen , dass :

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

Und jetzt kommen wir zu meinem Punkt: Wie Array(N)geht es den Dingen? Abschnitt 15.4.2.2 beschreibt den Prozess. Es gibt eine Menge Hokuspokus, die uns egal sind, aber wenn Sie es schaffen, zwischen den Zeilen zu lesen (oder Sie können mir in dieser Zeile einfach vertrauen, aber nicht), läuft es im Grunde darauf hinaus:

function Array(len) {
    var ret = [];
    ret.length = len;
    return ret;
}

(arbeitet unter der Annahme (die in der tatsächlichen Spezifikation überprüft wird), dass lenes sich um eine gültige uint32 handelt und nicht um eine beliebige Anzahl von Werten)

Jetzt können Sie sehen, warum dies Array(5).map(...)nicht funktioniert - wir definieren keine lenElemente im Array, wir erstellen keine key => valueZuordnungen, wir ändern einfach die lengthEigenschaft.

Nachdem wir das aus dem Weg geräumt haben, schauen wir uns die zweite magische Sache an:

2. Wie Function.prototype.applyfunktioniert

Im applyGrunde genommen wird ein Array genommen und als Argument eines Funktionsaufrufs abgewickelt. Das bedeutet, dass Folgendes ziemlich gleich ist:

function foo (a, b, c) {
    return a + b + c;
}
foo(0, 1, 2); //3
foo.apply(null, [0, 1, 2]); //3

Jetzt können wir den Prozess der Funktionsweise applyvereinfachen, indem wir einfach die argumentsspezielle Variable protokollieren :

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]

Es ist einfach, meine Behauptung im vorletzten Beispiel zu beweisen:

function ahaExclamationMark () {
    console.log(arguments.length);
    console.log(arguments.hasOwnProperty(0));
}

ahaExclamationMark.apply(null, Array(2)); //2, true

(Ja, Wortspiel beabsichtigt). Das key => valueMapping war möglicherweise nicht in dem Array vorhanden, an das wir übergeben haben apply, aber es ist sicherlich in der argumentsVariablen vorhanden. Es ist der gleiche Grund, warum das letzte Beispiel funktioniert: Die Schlüssel sind für das Objekt, das wir übergeben, nicht vorhanden, aber sie sind in vorhanden arguments.

Warum ist das so? Schauen wir uns Abschnitt 15.3.4.3 an , in dem Function.prototype.applydefiniert ist. Meistens Dinge, die uns egal sind, aber hier ist der interessante Teil:

  1. Sei len das Ergebnis des Aufrufs der internen Methode [[Get]] von argArray mit dem Argument "length".

Was im Grunde bedeutet : argArray.length. Die Spezifikation führt dann eine einfache forSchleife über lengthElemente durch und erstellt einen listder entsprechenden Werte ( listist ein interner Voodoo, aber im Grunde ist es ein Array). In Bezug auf sehr, sehr losen Code:

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);
};

argArrayIn diesem Fall müssen wir also nur ein Objekt mit einer lengthEigenschaft nachahmen . Und jetzt können wir sehen, warum die Werte undefiniert sind, die Schlüssel jedoch nicht. argumentsWir erstellen die key=>valueZuordnungen.

Puh, das war vielleicht nicht kürzer als der vorherige Teil. Aber wenn wir fertig sind, wird es Kuchen geben, also sei geduldig! Nach dem folgenden Abschnitt (der, wie ich verspreche, kurz sein wird) können wir jedoch beginnen, den Ausdruck zu zerlegen. Falls Sie es vergessen haben, war die Frage, wie Folgendes funktioniert:

Array.apply(null, { length: 5 }).map(Number.call, Number);

3. Wie geht man Arraymit mehreren Argumenten um?

So! Wir haben gesehen, was passiert, wenn Sie ein lengthArgument an übergeben Array, aber im Ausdruck übergeben wir mehrere Dinge als Argumente (ein Array von 5 undefined, um genau zu sein). In Abschnitt 15.4.2.1 erfahren Sie , was zu tun ist. Der letzte Absatz ist alles, was uns wichtig ist, und er ist wirklich seltsam formuliert , aber es läuft irgendwie auf Folgendes hinaus:

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! Wir erhalten ein Array mit mehreren undefinierten Werten und geben ein Array dieser undefinierten Werte zurück.

Der erste Teil des Ausdrucks

Schließlich können wir Folgendes entschlüsseln:

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

Wir haben gesehen, dass es ein Array zurückgibt, das 5 undefinierte Werte enthält, wobei alle Schlüssel vorhanden sind.

Nun zum zweiten Teil des Ausdrucks:

[undefined, undefined, undefined, undefined, undefined].map(Number.call, Number)

Dies wird der einfachere, nicht verschlungene Teil sein, da er nicht so sehr auf obskuren Hacks beruht.

4. Wie Numberbehandelt man Eingaben?

Doing Number(something)( Abschnitt 15.7.1 ) konvertiert somethingin eine Zahl, und das ist alles. Wie das geht, ist etwas kompliziert, besonders bei Strings, aber die Operation wird in Abschnitt 9.3 definiert, falls Sie interessiert sind.

5. Spiele von Function.prototype.call

callist sein applyBruder, definiert in Abschnitt 15.3.4.4 . Anstatt ein Array von Argumenten zu verwenden, werden nur die empfangenen Argumente verwendet und weitergeleitet.

Die Dinge werden interessant, wenn Sie mehr als eine callaneinander ketten und das Unheimliche auf 11 drehen:

function log () {
    console.log(this, arguments);
}
log.call.call(log, {a:4}, {a:5});
//{a:4}, [{a:5}]
//^---^  ^-----^
// this   arguments

Dies ist ziemlich wertvoll, bis Sie verstehen, was los ist. log.callist nur eine Funktion, die der callMethode einer anderen Funktion entspricht , und hat als solche auch eine callMethode für sich:

log.call === log.call.call; //true
log.call === Function.call; //true

Und was macht calldas? Es akzeptiert eine thisArgReihe von Argumenten und ruft seine übergeordnete Funktion auf. Wir können es definieren über apply (wieder sehr lockerer Code, funktioniert nicht):

Function.prototype.call = function (thisArg) {
    var args = arguments.slice(1); //I wish that'd work
    return this.apply(thisArg, args);
};

Lassen Sie uns verfolgen, wie dies abläuft:

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}])

Der spätere Teil oder das .mapvon allem

Es ist noch nicht vorbei. Mal sehen, was passiert, wenn Sie den meisten Array-Methoden eine Funktion bereitstellen:

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

Wenn wir selbst kein thisArgument angeben, wird standardmäßig verwendet window. Beachten Sie die Reihenfolge, in der die Argumente für unseren Rückruf bereitgestellt werden, und lassen Sie es uns noch einmal bis 11 verrückt machen:

arr.forEach(log.call, log);
//'a', [0, ['a', 'b', 'c']]
//'b', [1, ['a', 'b', 'c']]
//'b', [2, ['a', 'b', 'c']]
// ^    ^

Whoa whoa whoa ... lass uns ein bisschen zurücktreten. Was ist denn hier los? Wir können in Abschnitt 15.4.4.18 sehen , wo forEachFolgendes definiert ist:

var callback = log.call,
    thisArg = log;

for (var i = 0; i < arr.length; i += 1) {
    callback.call(thisArg, arr[i], i, arr);
}

Also, wir bekommen das:

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);

Jetzt können wir sehen, wie es .map(Number.call, Number)funktioniert:

Number.call.call(Number, arr[i], i, arr);
Number.call(arr[i], i, arr);
Number(i, arr);

Dies gibt die Umwandlung des iaktuellen Index in eine Zahl zurück.

Abschließend,

Der Ausdruck

Array.apply(null, { length: 5 }).map(Number.call, Number);

Arbeitet in zwei Teilen:

var arr = Array.apply(null, { length: 5 }); //1
arr.map(Number.call, Number); //2

Der erste Teil erstellt ein Array von 5 undefinierten Elementen. Der zweite geht über dieses Array und nimmt seine Indizes, was zu einem Array von Elementindizes führt:

[0, 1, 2, 3, 4]
Zirak
quelle
@ Zirak Bitte helfen Sie mir beim Verständnis der folgenden ahaExclamationMark.apply(null, Array(2)); //2, true. Warum zurückgeben 2und truejeweils? Übergeben Sie nicht nur ein Argument, dh Array(2)hier?
Geek
4
@Geek Wir übergeben nur ein Argument an apply, aber dieses Argument wird in zwei Argumente "aufgeteilt", die an die Funktion übergeben werden. Das sehen Sie leichter an den ersten applyBeispielen. Das erste console.logzeigt dann, dass wir tatsächlich zwei Argumente erhalten haben (die beiden Array-Elemente), und das zweite console.logzeigt, dass das Array eine key=>valueZuordnung im 1. Slot hat (wie im 1. Teil der Antwort erläutert).
Zirak
4
Aufgrund (einiger) Anfragen können Sie jetzt die Audioversion genießen: dl.dropboxusercontent.com/u/24522528/SO-answer.mp3
Zirak
1
Beachten Sie, dass das Übergeben einer NodeList, bei der es sich um ein Hostobjekt handelt, an eine native Methode wie in log.apply(null, document.getElementsByTagName('script'));nicht erforderlich ist, um in einigen Browsern zu funktionieren, und dass das [].slice.call(NodeList)Verwandeln einer NodeList in ein Array auch in diesen nicht funktioniert.
RobG
2
Eine Korrektur: thisStandardmäßig nur Windowim nicht strengen Modus.
ComFreek
21

Haftungsausschluss : Dies ist eine sehr formale Beschreibung des obigen Codes - so kann ich ihn erklären. Für eine einfachere Antwort - überprüfen Sie Ziraks großartige Antwort oben. Dies ist eine detailliertere Spezifikation in Ihrem Gesicht und weniger "Aha".


Hier passieren mehrere Dinge. Lassen Sie es uns ein bisschen aufbrechen.

var arr = Array.apply(null, { length: 5 }); // Create an array of 5 `undefined` values

arr.map(Number.call, Number); // Calculate and return a number based on the index passed

In der ersten Zeile wird der Array-Konstruktor als Funktion mit aufgerufenFunction.prototype.apply .

  • Der thisWert nullspielt für den Array-Konstruktor keine Rolle ( thisist der gleiche thiswie im Kontext gemäß 15.3.4.3.2.a.
  • Dann new Arraywird das Übergeben eines Objekts mit einer lengthEigenschaft aufgerufen - das bewirkt, dass dieses Objekt ein Array ist, wie es für alles wichtig ist, .applyaufgrund der folgenden Klausel in .apply:
    • Sei len das Ergebnis des Aufrufs der internen Methode [[Get]] von argArray mit dem Argument "length".
  • Übergibt als solches .applyArgumente von 0 an.length , seit dem Aufruf [[Get]]auf{ length: 5 } mit den Werten 0 bis 4 Ausbeuten undefineddes Array - Konstruktor ist mit fünf Argumenten , dessen Wert aufgerufen ist undefined(eine nicht deklarierte Eigenschaft eines Objekts erhalten).
  • Der Array-Konstruktor wird mit 0, 2 oder mehr Argumenten aufgerufen . Die Längeneigenschaft des neu erstellten Arrays wird auf die Anzahl der Argumente gemäß der Spezifikation und die Werte auf dieselben Werte festgelegt.
  • So var arr = Array.apply(null, { length: 5 }); wird eine Liste mit fünf undefinierten Werten erstellt.

Hinweis : Beachten Sie hier den Unterschied zwischen Array.apply(0,{length: 5})und Array(5), wobei der erste das Fünffache des primitiven Werttyps erstellt und der zweite undefinedein leeres Array der Länge 5 erstellt. Insbesondere wegen.map Werttyps erstellt Verhaltens von (8.b) und der und speziell [[HasProperty].

Der obige Code in einer kompatiblen Spezifikation ist also der gleiche wie:

var arr = [undefined, undefined, undefined, undefined, undefined];
arr.map(Number.call, Number); // Calculate and return a number based on the index passed

Nun zum zweiten Teil.

  • Array.prototype.mapRuft die Rückruffunktion (in diesem Fall Number.call) für jedes Element des Arrays auf und verwendet den angegebenen thisWert (in diesem Fall wird diethis Wert auf `Number gesetzt).
  • Der zweite Parameter des Rückrufs in der Karte (in diesem Fall Number.call ) ist der Index, und der erste ist dieser Wert.
  • Dies bedeutet, dass Numbermit thisas undefined(dem Array-Wert) und dem Index als Parameter aufgerufen wird. Es ist also im Grunde dasselbe wie die Zuordnung jedes undefinedArrays zu seinem Array-Index (da der Aufruf Numbereine Typkonvertierung durchführt, in diesem Fall von Nummer zu Nummer, ohne den Index zu ändern).

Daher nimmt der obige Code die fünf undefinierten Werte und ordnet sie jeweils ihrem Index im Array zu.

Deshalb erhalten wir das Ergebnis zu unserem Code.

Benjamin Gruenbaum
quelle
1
Für Dokumente: Spezifikation für die Funktionsweise der Karte: es5.github.io/#x15.4.4.19 Mozilla verfügt über ein Beispielskript, das gemäß dieser Spezifikation unter developer.mozilla.org/en-US/docs/Web/JavaScript/
Patrick Evans
1
Aber warum funktioniert es nur mit Array.apply(null, { length: 2 })und nicht mit Array.apply(null, [2])dem ArrayKonstruktor, der 2als Längenwert übergeben wird? Geige
Andreas
@Andreas Array.apply(null,[2])ist so, Array(2)dass ein leeres Array der Länge 2 erstellt wird und kein Array, das den primitiven Wert undefinedzweimal enthält. Sehen Sie sich meine letzte Bearbeitung in der Notiz nach dem ersten Teil an. Lassen Sie mich wissen, ob es klar genug ist, und wenn nicht, werde ich das klarstellen.
Benjamin Gruenbaum
Ich habe nicht verstanden, wie es beim ersten Durchlauf funktioniert ... Nach der zweiten Lesung macht es Sinn. {length: 2}fälscht ein Array mit zwei Elementen, die der ArrayKonstruktor in das neu erstellte Array einfügen würde. Da es kein echtes Array gibt, das auf die nicht vorhandenen Elemente zugreift, ergibt sich, undefinedwas dann eingefügt wird. Schöner Trick :)
Andreas
5

Wie Sie sagten, der erste Teil:

var arr = Array.apply(null, { length: 5 }); 

Erstellt ein Array mit 5 undefinedWerten.

Der zweite Teil ruft die mapFunktion des Arrays auf, die zwei Argumente akzeptiert und ein neues Array derselben Größe zurückgibt.

Das erste Argument, das mapbenötigt wird, ist eine Funktion, die auf jedes Element im Array angewendet werden soll. Es wird erwartet, dass es sich um eine Funktion handelt, die drei Argumente akzeptiert und einen Wert zurückgibt. Beispielsweise:

function foo(a,b,c){
    ...
    return ...
}

Wenn wir die Funktion foo als erstes Argument übergeben, wird sie für jedes Element mit aufgerufen

  • a als Wert des aktuell iterierten Elements
  • b als Index des aktuell iterierten Elements
  • c als das gesamte ursprüngliche Array

Das zweite Argument mapwird an die Funktion übergeben, die Sie als erstes Argument übergeben. Aber es wäre weder a, b noch c, wenn fooes so wäre this.

Zwei Beispiele:

function bar(a,b,c){
    return this
}
var arr2 = [3,4,5]
var newArr2 = arr2.map(bar, 9);
//newArr2 is equal to [9,9,9]

function baz(a,b,c){
    return b
}
var newArr3 = arr2.map(baz,9);
//newArr3 is equal to [0,1,2]

und noch eine, um es klarer zu machen:

function qux(a,b,c){
    return a
}
var newArr4 = arr2.map(qux,9);
//newArr4 is equal to [3,4,5]

Was ist also mit Number.call?

Number.call ist eine Funktion, die 2 Argumente akzeptiert und versucht, das zweite Argument auf eine Zahl zu analysieren (ich bin nicht sicher, was es mit dem ersten Argument macht).

Da das zweite übergebene Argument mapder Index ist, entspricht der Wert, der an diesem Index in das neue Array eingefügt wird, dem Index. Genau wie die Funktion bazim obigen Beispiel.Number.callwird versuchen, den Index zu analysieren - es wird natürlich den gleichen Wert zurückgeben.

Das zweite Argument, das Sie mapin Ihrem Code an die Funktion übergeben haben, wirkt sich nicht auf das Ergebnis aus. Korrigieren Sie mich bitte, wenn ich falsch liege.

Tal Z.
quelle
1
Number.callist keine spezielle Funktion, die Argumente nach Zahlen analysiert. Es ist einfach === Function.prototype.call. Nur das zweite Argument, die Funktion , die als übergeben wird , thisum -Wertes call, ist relevant - .map(eval.call, Number), .map(String.call, Number)und .map(Function.prototype.call, Number)alle sind gleichwertig.
Bergi
0

Ein Array ist einfach ein Objekt, das das Feld 'Länge' und einige Methoden (z. B. Push) umfasst. Arr in var arr = { length: 5}ist also im Grunde dasselbe wie ein Array, in dem die Felder 0..4 den undefinierten Standardwert haben (dh arr[0] === undefinedtrue ergeben).
Wie der Name schon sagt, wird im zweiten Teil von einem Array ein neues zugeordnet. Dies geschieht durch Durchlaufen des ursprünglichen Arrays und Aufrufen der Zuordnungsfunktion für jedes Element.

Sie müssen Sie nur noch davon überzeugen, dass das Ergebnis der Mapping-Funktion der Index ist. Der Trick besteht darin, die Methode 'call' (*) zu verwenden, die eine Funktion aufruft, mit der kleinen Ausnahme, dass der erste Parameter als 'this'-Kontext festgelegt ist und der zweite zum ersten Parameter wird (und so weiter). Zufälligerweise ist der zweite Parameter der Index, wenn die Zuordnungsfunktion aufgerufen wird.

Last but not least wird als Methode die Zahl "Klasse" aufgerufen, und wie wir in JS wissen, ist eine "Klasse" einfach eine Funktion, und diese (Zahl) erwartet, dass der erste Parameter der Wert ist.

(*) im Prototyp von Function gefunden (und Number ist eine Funktion).

MASHAL

shex
quelle
1
Es gibt einen großen Unterschied zwischen [undefined, undefined, undefined, …]und new Array(n)oder {length: n}- die letzteren sind spärlich , dh sie haben keine Elemente. Dies ist sehr relevant für map, und deshalb wurde die ungerade Array.applyverwendet.
Bergi