2011-12-16 11 views
8

Stavo cercando di ridurre il mio codice memorizzando le funzioni in cache alle variabili. Per esempio:"oggetto non è una funzione" quando si salva function.call su una variabile

function test(){ 
    var a = Array.prototype.slice, 
    b = a.call(arguments); 
    // Do something 
    setTimeout(function(){ 
    var c = a.call(arguments); 
    // Do something else 
    }, 200); 
} 

Così, invece di chiamare Array.prototype.slice.call(arguments), posso solo fare a.call(arguments);.

Stavo cercando di renderlo ancora più piccolo memorizzando nella cache Array.prototype.slice.call, ma non funzionava.

function test(){ 
    var a = Array.prototype.slice.call, 
    b = a(arguments); 
    // Do something 
    setTimeout(function(){ 
    var c = a(arguments); 
    // Do something else 
    }, 200); 
} 

Questo mi dà TypeError: object is not a function. Perché?

typeof Array.prototype.slice.call restituisce "function", come previsto.

Perché non è possibile salvare .call in una variabile (quindi chiamarla)?

+0

quale motore javascript ti ha dato questo errore? –

+0

possibile duplicato di [Come si fa riferimento a Array.prototype.slice.call()?] (Http://stackoverflow.com/questions/6835315/how-do-you-reference-array-prototype-slice-call) – pimvdb

+0

@DanD .: Chrome 16. –

risposta

7

Function.prototype.call è una funzione ordinaria che opera la funzione passata come this.

Quando si chiama call da una variabile, this diventa window, che non è una funzione.
è necessario scrivere call.call(slice, someArray, arg1, arg2)

+0

Neat, funziona. 'var a = Array.prototype.slice, b = a.call; b.call (a, argomenti) '. Quindi, c'è un modo per "legare" questo quando si copia '.call'? –

+2

@Rocket: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind – SLaks

+0

Quindi, 'var a = Array.prototype.slice.call.bind (Array.prototype.slice)'?Edit: Wow, che funziona davvero! Modifica 2: in base alla pagina 'var slice = Function.prototype.call.bind (Array.prototype.slice);' funziona anche! Neat! –

5

Prova questo:

function test(){ 
    var a = function(args){ 
     return Array.prototype.slice.call(args); 
    }; 
    b = a(arguments); 
    // Do something 
    setTimeout(function(){ 
    var c = a(arguments); 
    // Do something else 
    }, 200); 
} 

Lo stesso errore accadrà se si tenta di fare qualcosa di simile:

var log = console.log; 
log("Hello"); 

il motivo è che quando si esegue questa operazione si sta assegnando la funzione x (nel mio esempio log) alla variabile log. MA la funzione contiene una chiamata a this che ora si riferisce a window e non console, che poi genera un errore che this is not an object

+0

Strano, 'var log = console.log; log ('a'); 'fornisce' TypeError: Illegal invocation' in Chrome 16, ma 'var logX = console.log.bind (console); logX ('a'); 'works :-P –

4

Il problema è che call è un metodo (una funzione che appartiene a un oggetto), che si aspetta che il suo proprietario (il suo this) per una funzione. Quando scrivi a = Array.prototype.slice.call, stai copiando la funzione, ma non il proprietario.

Il messaggio "oggetto non è una funzione" non sta dicendo che a non è una funzione, ma sta dicendo che il suo this non è una funzione. Potresti tecnicamente ottenere ciò che descrivi scrivendo a.call(Array.prototype.slice, arguments), ma ovviamente non è quello che vuoi!

+0

Fresco, 'a.call (Array.prototype.slice, argomenti)' funziona davvero. Ho pensato che quando hai copiato una funzione, questo sarebbe stato referenziato correttamente. –

+2

@Rocket: No - non può essere - perché dobbiamo essere in grado di fare qualcosa come 'a.foo = b.foo' o' A.prototype.foo = B.prototype.foo' o cosa no a copia un metodo da un oggetto a un altro. Sarebbe terribilmente confuso se una chiamata a 'a.foo()' operasse su 'b' piuttosto che' a'! – ruakh

Problemi correlati