2009-01-31 9 views
5

natknąłem javascript puzzle pytając: napisać kawałek jednej linii kodu JavaScript, który skleja wszystkie sznurki przekazywane do funkcji:
rekurencyjnie złączenie javascript funkcje argumenty

 

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

@meebo

Widząc, że argumenty funkcji są reprezentowane jako indeksowany obiekt MAYBE w tablicy, myślałem, że można to zrobić w sposób rekursywny. Jednak moja rekurencyjna implementacja rzuca błąd. - „conc.arguments.shift nie jest funkcją” -

 

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

wydaje się, że conc.arguments nie jest tablicą, ale mogą być dostępne przez indeks numer i ma właściwość length ??? mylące - prosimy o dzielenie się opiniami i innymi rekurencyjnymi wdrożeniami.

Dzięki

Odpowiedz

12

argumentsis said to be obiekt Array-podobne. Jak już zauważyłeś, możesz uzyskać dostęp do jego elementów według indeksu, ale nie masz do dyspozycji wszystkich metod Array. Inne przykłady obiektów podobnych do Array to kolekcje HTML zwracane przez getElementsByTagName() lub getElementsByClassName(). jQuery, jeśli kiedykolwiek go używałeś, jest również obiektem podobnym do Array. Po wysłaniu zapytania do niektórych obiektów DOM, sprawdź wynikowy obiekt jQuery za pomocą Firebug w zakładce DOM, a zobaczysz co mam na myśli.

Oto moje rozwiązanie problemu 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) jest miły podstęp przekształcić naszą arguments w prawdziwą obiekt Array. W przeglądarce Firefox Array.slice.call(arguments) wystarczy, ale nie będzie działać w IE6 (przynajmniej), więc poprzednia wersja jest zwykle używana.Również ta sztuczka nie działa dla kolekcji zwróconej przez metody DOM API w IE6 (przynajmniej); spowoduje błąd. By the way, zamiast call można użyć apply.

Małe wyjaśnienie na temat obiektów podobnych do Array. W JavaScript można użyć prawie wszystkiego, aby nazwać członków obiektu, a liczby nie są wyjątkiem. Więc można zbudować obiekt, który wygląda jak ten, który jest całkowicie poprawny JavaScript:

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

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

    length : 1 
} 

Powyższy cel jest obiektem Array-jak z dwóch powodów:

  1. Ma członków, których nazwy są numery , tak jak są one indeksów Array
  2. ma właściwości length, bez którego nie można przekształcić obiekt w prawdziwym Array konstruktem: Array.prototype.slice.call(Foo);

Obiekt arguments obiektu Function jest podobny do obiektu Foo, tyle że ma swój specjalny cel.

+0

Dostaję obiekt oczekiwany błąd na slice.call w IE –

1

Lista argumentów nie jest oryginalną tablicą. Myślę, że możesz wypożyczyć metody tablicowe i użyć ich w argumentach z "call" lub "apply".

7

Mozilla on the subject:

Argumenty obiekt nie jest tablicą. To jest jest podobne do tablicy, ale nie ma żadnych właściwości tablicy poza długością. Na przykład nie ma metody pop. Jednak może to być konwertowane do rzeczywistej tablicy:

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

Dlatego rozwiązanie problemu jest dość proste:

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

BTW: to kolejne stany:

Obiekt arguments jest lokalną zmienną dostępną w ramach wszystkich funkcji ; argumenty jako właściwość Funkcja nie może być dłużej używana.

Należy używać tylko arguments zamiast func.arguments

+0

Dlaczego się argumenty do prawdziwej tablicy? Zastanawiam się, jak szybko kawałek jest .. – svinto

1

Można to zrobić:

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

to działa:

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

Dlaczego nie wywołujesz funkcji z 3 argumentami łańcuchowymi zamiast 1 argumentu tablicowego z 3 ciągami? To by pozbyć się przecinka :) Bardzo podoba mi się to rozwiązanie. +1 –

+0

Bo jestem zmęczony i chory! Dzięki za wskazanie mojej głupoty, teraz działa. – svinto

+0

Działa, ale nie jest rekurencyjny! – Nosredna

Powiązane problemy