2009-01-31 14 views
5

mi sono imbattuto in un puzzle javascript chiedendo: scrivere un pezzo di una sola riga di codice JavaScript che concatena tutte le stringhe passate in una funzione:
ricorsivamente concatenando a funzioni JavaScript argomenti

 

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

@meebo

Vedendo che gli argomenti della funzione sono rappresentati come un oggetto indicizzato FORSE una matrice, ho pensato che si può fare in modo ricorsivo. Tuttavia la mia implementazione ricorsiva sta generando un errore. - "conc.arguments.shift non è una funzione" -

 

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

sembra come se conc.arguments non è un array, ma può essere letta da un indice numero ed ha una proprietà length ??? confusione - si prega di condividere opinioni e altre implementazioni ricorsive.

Grazie

risposta

12

argumentsis said to be un oggetto Array-like. Come hai già visto, puoi accedere ai suoi elementi per indice, ma non hai tutti i metodi di Array a tua disposizione. Altri esempi di oggetti tipo Array sono raccolte HTML restituite da getElementsByTagName() o getElementsByClassName(). jQuery, se lo hai mai usato, è anche un oggetto simile ad Array. Dopo aver interrogato alcuni oggetti DOM, ispeziona l'oggetto jQuery risultante con Firebug nella scheda DOM e vedrai cosa intendo.

Ecco la mia soluzione per il problema 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) è un bel trucco per trasformare la nostra arguments in un vero e proprio oggetto Array. In Firefox Array.slice.call(arguments) sarebbe sufficiente, ma non funzionerà in IE6 (almeno), quindi la versione precedente è ciò che viene solitamente utilizzato.Inoltre, questo trucco non funziona per la raccolta restituita dai metodi API DOM in IE6 (almeno); genererà un errore. A proposito, invece di call si potrebbe usare apply.

Una piccola spiegazione sugli oggetti tipo Array. In JavaScript puoi usare praticamente qualsiasi cosa per nominare i membri di un oggetto, ei numeri non sono un'eccezione. Così si può costruire un oggetto che assomiglia a questo, che è perfettamente valida JavaScript:

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

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

    length : 1 
} 

L'oggetto di cui sopra è un oggetto Array simile per due motivi:

  1. Ha i membri che i nomi sono numeri , quindi sono come indici di array
  2. ha una proprietà length, senza la quale non si può trasformare l'oggetto in un vero e proprio Array con il costrutto: Array.prototype.slice.call(Foo);

L'oggetto arguments di un oggetto Function è praticamente come l'oggetto Foo, solo che ha uno scopo speciale.

+0

Ottengo un errore atteso oggetto su slice.call in IE –

1

L'elenco degli argomenti non è un array originale. Penso che puoi prendere in prestito i metodi dell'array e usarli su argomenti con "call" o "apply".

7

Mozilla on the subject:

Gli argomenti oggetto non è un array. È simile a un array, ma non ha alcuna proprietà dell'array eccetto la lunghezza. Ad esempio, non ha il metodo pop. Tuttavia può essere convertito in un vero matrice:

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

Quindi la soluzione al problema è piuttosto semplice:

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

proposito: precisa inoltre:

L'oggetto arguments è una variabile locale disponibile in tutte le funzioni ; argomenti come una proprietà di La funzione non può più essere utilizzata.

Si dovrebbe utilizzare solo arguments invece di func.arguments

+0

Perché fare gli argomenti in un vero array? Mi chiedo quanto sia veloce la fetta ... – svinto

1

Si potrebbe fare questo:

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

Questo funziona:

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

Perché non stai chiamando la funzione con 3 argomenti stringa invece di 1 argomento array con 3 stringhe? Questo eliminerebbe le virgole :) Mi piace molto questa soluzione. +1 –

+0

Perché sono stanco e malato! Grazie per aver segnalato la mia stupidità, ora funziona. – svinto

+0

Funziona, ma non è ricorsivo! – Nosredna

Problemi correlati