2009-01-31 15 views
5

ich über ein Javascript Puzzle kam zu fragen: schreibt ein einzeiliges Stück JavaScript-Code, der all Strings verkettet in eine Funktion übergeben:
rekursiv ein JavaScript-Funktionen Argumente verketten

 

    function concatenate(/*any number of strings*/) { 
     var string = /*your one line here*/ 
     return string; 
    } 
 

@meebo

Wenn man bedenkt, dass die Funktionsargumente als ein indiziertes Objekt dargestellt sind, kann ein Array, denke ich, rekursiv gemacht werden. Meine rekursive Implementierung wirft jedoch einen Fehler auf. - „conc.arguments.shift ist keine Funktion“ -

 

    function conc(){ 
     if (conc.arguments.length === 0) 
      return ""; 
     else 
      return conc.arguments.shift() + conc(conc.arguments); 
} 
 

es, als ob conc.arguments scheint kein Array ist, können aber durch eine Anzahl Index und hat eine Länge Eigenschaft zugegriffen werden ??? verwirrend - bitte teile Meinungen und andere rekursive Implementierungen.

Danke

Antwort

12

argumentsis said to be ein Array-ähnlichen Objekt. Wie Sie bereits gesehen haben, können Sie auf seine Elemente per Index zugreifen, aber Sie haben nicht alle Array-Methoden zur Verfügung. Andere Beispiele für arrayähnliche Objekte sind HTML-Auflistungen, die von getElementsByTagName() oder getElementsByClassName() zurückgegeben werden. jQuery, wenn Sie es jemals benutzt haben, ist auch ein Array-ähnliches Objekt. Überprüfen Sie nach dem Abfragen einiger DOM-Objekte das resultierende jQuery-Objekt mit Firebug auf der Registerkarte DOM und Sie werden sehen, was ich meine.

Hier ist meine Lösung für das Problem Meebo:

function conc(){ 
    if (arguments.length === 0) 
     return ""; 
    else 
     return Array.prototype.slice.call(arguments).join(" "); 
} 

alert(conc("a", "b", "c")); 

Array.prototype.slice.call(arguments) ein netter Trick ist unser arguments in ein wahres Array-Objekt zu verwandeln. In Firefox Array.slice.call(arguments) würde ausreichen, aber es wird nicht funktionieren in IE6 (zumindest), so ist die frühere Version, was normalerweise verwendet wird.Dieser Trick funktioniert auch nicht für die Sammlung, die von DOM-API-Methoden in IE6 (mindestens) zurückgegeben wird; Es wird einen Fehler auslösen. By the way, anstelle von call könnte man apply verwenden.

Eine kleine Erklärung über Array-ähnliche Objekte. In JavaScript können Sie so ziemlich alles verwenden, um die Mitglieder eines Objekts zu benennen, und Zahlen sind keine Ausnahme. So ein Objekt konstruieren kann, die so aussieht, die perfekt gültig JavaScript ist:

var Foo = { 
    bar : function() { 
     alert('I am bar'); 
    }, 

    0 : function() { 
     alert('I am 1'); 
    }, 

    length : 1 
} 

Die obige Aufgabe ist ein Array-ähnliches Objekt aus zwei Gründen:

  1. Es hat Zahlen Mitglieder, die Namen sind , so dass sie wie Array-Indizes
  2. Es hat eine length Eigenschaft, ohne die Sie nicht das Objekt in ein wahres Array mit dem Konstrukt verwandeln: Array.prototype.slice.call(Foo);

Das arguments-Objekt eines Function-Objekts ähnelt in etwa dem Foo-Objekt, nur dass es seinen speziellen Zweck hat.

+0

Ich erhalte einen Objekt Erwartete Fehler auf Scheibe.call in IE –

1

Die Liste der Argumente ist kein echtes Array. Ich denke, Sie können die Array-Methoden ausleihen und sie für Argumente mit "Call" oder "Apply" verwenden.

7

Mozilla on the subject:

Die Argumente Objekt nicht ein Array. Es ähnelt einem Array, hat aber kein Array Eigenschaften außer Länge. Zum Beispiel hat es nicht die Pop-Methode. Allerdings kann es zu einer echten Array umgewandelt werden:

var args = Array.prototype.slice.call(arguments); 

Deshalb ist die Lösung für Ihr Problem ist recht einfach:

var string = Array.prototype.slice.call(arguments).join(""); 

BTW: Weiter heißt es:

Das Argumentobjekt ist eine lokale Variable, die in allen Funktionen verfügbar ist; Argumente als Eigenschaft von Funktion kann nicht mehr verwendet werden.

Sie sollten nur arguments anstelle von func.arguments

+0

Warum Argumente in eine reale Array machen? Ich frage mich, wie schnell Scheibe ist .. – svinto

1

Sie können dies tun:

function concatenate() { 
    if (arguments.length > 1) { 
     return arguments[0] + concatenate.apply(this, Array.prototype.splice.call(arguments, 1)); 
    } 
    return arguments[0]; 
} 
6

Dies funktioniert:

function concatenate(){ 
    return [].join.call(arguments, ""); 
} 
alert(concatenate("one", "two", "three")); 
+0

Warum rufen Sie nicht die Funktion mit 3 String-Argumente anstelle von 1 Array-Argument mit 3 Strings? Das würde die Kommas loswerden :) Ich mag diese Lösung wirklich. +1 –

+0

Weil ich müde und krank bin! Danke, dass du meine Dummheit aufgezeigt hast, jetzt funktioniert es. – svinto

+0

Es funktioniert, aber es ist nicht rekursiv! – Nosredna