2015-05-26 20 views
8

Supponiamo di avere la seguente funzione:argomenti Javascript mutevoli

var a = function(data, type){ 
 
    var shift = [].shift; 
 
    shift.call(arguments); 
 
    shift.call(arguments); 
 
    shift.call(arguments); 
 
    shift.call(arguments); 
 
    console.log(data); 
 
} 
 

 
a(1,'test', 2, 3);

ho capito che i dati e il tipo sono solo riferimenti a valori specifici argomenti. Ma perché alla fine, i dati sono pari a 3?

+0

La relazione tra di loro è attiva ... la soluzione è utilizzare un array separato come 'var arr = [] .slice.call (argomenti)' then 'shift.call (arr)' –

+0

So di connessione:) Sono interessato perché alla fine non è indefinito ma 3 – dimko1

+0

perché quando si chiama shift la posizione di tutti i valori nell'elenco dei parametri formale cambia –

risposta

3

Da https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode#Making_eval_and_arguments_simpler:

modalità Strict rende arguments meno bizzarro magico.

Nel codice normale in una funzione il cui primo argomento è arg, modificando arg imposta anche arguments[0], e viceversa (meno che non argomenti sono stati forniti o arguments[0] viene eliminato).

arguments oggetti per funzioni in modalità rigorosa archiviano gli argomenti originali quando la funzione è stata richiamata. arguments[i] non traccia il valore dell'argomento con nome corrispondente, né un argomento con nome traccia il valore nel corrispondente arguments[i].

In realtà si è riunito il "a meno che gli argomenti [i] è cancellato" caso;)

+0

Link eccellente, questo è anche nel riferimento EcmaScript effettivo. Vedi la mia risposta http://stackoverflow.com/a/30459615/227299 –

2

Quello che ottieni è un array di argomenti con [data, type] e altri due argomenti non utilizzati. Aggiungi un console.log prima e dopo ogni turno e vedrai cosa succede;

var shift = [].shift; 
console.log("args", arguments) 
console.log(data, type); 
// Outputs [1, 'test', 2, 3] => data = 1, type = 'test' 

shift.call(arguments); 
console.log("args", arguments) 
console.log(data, type); 
// Outputs ['test', 2, 3] => data = 'test', type = 2 

shift.call(arguments); 
console.log("args", arguments) 
console.log(data, type); 
// Outputs [2, 3] => data = 2, type = 3 

shift.call(arguments); 
console.log("args", arguments) 
console.log(data, type); 
// Outputs [3] => data = 3, type = 3 (type is keeping it's old value) 

shift.call(arguments); 
console.log("args", arguments) 
console.log(data, type); 
// Outputs [] => data = 3, type = 3 (both are keeping their old value) 

Questo aiuto?

+0

è un comportamento imprevedibile imho –

+0

Ha svalutato questo, ma c'è una spiegazione reale ... Vedi http://stackoverflow.com/a/30459615/227299 e http://stackoverflow.com/a/30459864/227299 –

0

Ecco un passaggio del codice.

var a = function(data, type){ 
    var shift = [].shift;//data points to arguments[0], or 1 
    shift.call(arguments); // arguments[0] is now 'test' 
    shift.call(arguments); // arguments[0] is now 2 
    shift.call(arguments); //arguments[0] is now 3 
    shift.call(arguments); // data pointed @ 3, arguments[0] is undefined 
    console.log(data); 
} 

a(1,'test', 2, 3); 

JS sembra fare un lavoro in background, dove se l'indice corrispondente arguments (che non è un array) va da truthy a falsy/definito, il valore precedente viene mantenuto.

0

Quello che stai osservando è vero solo per JavaScript non severo, quindi non dovrebbe essere invocato. Vedi http://www.ecma-international.org/ecma-262/5.1/#sec-10.6, c'è una sezione che spiega il diverso comportamento tra modalità rigida e non rigida.

Sp00m inviato un nice explanation from MDN

Dalla descrizione EcmaScript

NOTA 1: Per non severe funzioni del modo l'indice di matrice (definito in 15.4) denominato proprietà dei dati di un argomenti oggetto i cui valori di nome numerico sono inferiori al numero di parametri formali dell'oggetto funzione corrispondente inizialmente condividono i loro valori con i collegamenti di argomento corrispondenti nel contesto di esecuzione della funzione. Ciò significa che la modifica della proprietà modifica il valore corrispondente del binding dell'argomento e vice-versa. Questa corrispondenza è interrotta se tale proprietà viene cancellata e quindi ridefinita o se la proprietà viene modificata in una proprietà accessoria. Per le funzioni in modalità rigorosa, i valori delle proprietà dell'oggetto arguments sono semplicemente una copia degli argomenti passati alla funzione e non esiste alcun collegamento dinamico tra i valori delle proprietà e i valori dei parametri formali.

var a = function(data, type){ 
 
    var shift = [].shift; 
 
    shift.call(arguments); 
 
    shift.call(arguments); 
 
    shift.call(arguments); 
 
    shift.call(arguments); 
 
    console.log(data); 
 
} 
 

 
var b = function(data, type){ 
 
    'use strict'; 
 
    var shift = [].shift; 
 
    shift.call(arguments); 
 
    shift.call(arguments); 
 
    shift.call(arguments); 
 
    shift.call(arguments); 
 
    console.log(data); 
 
} 
 

 
a(1,'test', 2, 3); // 3 
 
b(1,'test', 2, 3); // 1

0

Nel tuo caso 'dati' è un riferimento alla prima posizione dell'array argomenti. Quando si chiama la funzione i valori sono

arguments[0] => data => 1 
arguments[1] => type => 'test' 
arguments[2] => 2 
arguments[3] => 3 

Il docs dice che funzione di matrice spostare rimuove il primo elemento. Ma dice anche

lo spostamento è intenzionalmente generico; questo metodo può essere chiamato o applicato a oggetti che assomigliano a matrici. Gli oggetti che non contengono una proprietà di lunghezza che riflette l'ultimo di una serie di proprietà numeriche consecutive e basate su zero potrebbero non comportarsi in alcun modo significativo.

Internamente le funzioni di spostamento chiamano l'operatore di cancellazione. Dopo l'applicazione quattro volte l'array di argomenti è [indefinito, non definito]. Ora la cosa è che chiamare delete su una variabile rimuove ma se c'è ancora un riferimento alla variabile il valore non viene rimosso

delete arguments[0]; 
delete arguments[1]; 
console.log(arguments); => [2: 2, 3: 3] // Position 0 and 1 were removed. Lenght is still 4 
console.log(data); => 1 
console.log(type); => 'test' 

in modo da vedere le variabili sono ancora in fase di riferimento indipendentemente ti ha eliminato il valore da argomenti.

Problemi correlati