Passa le variabili per riferimento in Javascript

Come faccio a passare le variabili per riferimento in JS? Ho 3 variabili che voglio eseguire diverse operazioni per cui voglio metterle in un ciclo for ed eseguire le operazioni su ognuna.

codice pseudo:

myArray = new Array(var1, var2, var3); for (var x = 0; x < myArray.length; x++){ //do stuff to the array makePretty(myArray[x]); } //now do stuff to the updated vars 

Qual è il modo migliore per farlo?

Non esiste un “passaggio per riferimento” disponibile in JavaScript. È ansible passare un object (vale a dire, è ansible passare un valore a un riferimento a un object) e quindi disporre di una funzione per modificare il contenuto dell’object:

 function alterObject(obj) { obj.foo = "goodbye"; } var myObj = { foo: "hello world" }; alterObject(myObj); alert(myObj.foo); // "goodbye" instead of "hello world" 

Ora, nel tuo caso, non stai passando comunque niente, per quanto posso dire. È ansible scorrere le proprietà di un array con un indice numerico e modificare ciascuna cella dell’array, se lo si desidera.

È importante notare che “pass-by-reference” è un termine molto specifico. Ciò non significa semplicemente che è ansible passare un riferimento a un object modificabile. Invece, significa che è ansible passare una variabile semplice in modo tale da consentire a una funzione di modificare quel valore nel contesto di chiamata . Così:

  function swap(a, b) { var tmp = a; a = b; b = tmp; //assign tmp to b } var x = 1, y = 2; swap(x, y); alert("x is " + x + " y is " + y); // "x is 1 y is 2" 

In una lingua come C ++, è ansible farlo perché quella lingua ha (sort-of) pass-by-reference.

edit – questo recentemente (marzo 2015) è tornato su Reddit di nuovo su un post del blog simile al mio menzionato di seguito, anche se in questo caso su Java. Mi è venuto in mente che mentre leggevo il retro-e-avanti nei commenti di Reddit, gran parte della confusione deriva dalla sfortunata collisione che coinvolge la parola “riferimento”. La terminologia “passa per riferimento” e “passa per valore” precede il concetto di “oggetti” con cui lavorare in linguaggi di programmazione. In realtà non si tratta di oggetti; si tratta di parametri di funzione, e in particolare di come i parametri di funzione sono “connessi” (o meno) all’ambiente di chiamata. In particolare, si noti che in un vero linguaggio pass-by-reference – uno che coinvolge oggetti – si avrà ancora la possibilità di modificare il contenuto dell’object, e sembrerebbe esattamente esattamente come in JavaScript. Tuttavia, si sarebbe anche in grado di modificare il riferimento all’object nell’ambiente chiamante, e questa è la cosa fondamentale che non è ansible fare in JavaScript. Un linguaggio pass-by-reference non passerebbe il riferimento stesso, ma un riferimento al riferimento .

modifica – ecco un post sul blog sull’argomento. (Si noti il ​​commento a quel post che spiega che C ++ non ha realmente un riferimento pass-by.Questo è vero.Che cosa ha C ++, tuttavia, è la capacità di creare riferimenti a variabili semplici, esplicitamente nel punto di funzione invocazione per creare un puntatore, o implicitamente quando si chiamano funzioni il cui tipo di argomento firma richiede che venga eseguito. Queste sono le cose che JavaScript non supporta).

  1. le variabili di tipo primitive come stringhe e numeri vengono sempre passate per valore.
  2. Le matrici e gli oggetti vengono passati per riferimento o per valore in base a queste condizioni:

    • se si imposta il valore di un object o di un array, passa per valore.

      object1 = {prop: "car"}; array1 = [1,2,3];

    • se stai modificando un valore di una proprietà di un object o di un array, allora passa per riferimento.

      object1.prop = "car"; array1[0] = 9;

Codice

 function passVar(obj1, obj2, num) { obj1.prop = "laptop"; // will CHANGE original obj2 = { prop: "computer" }; //will NOT affect original num = num + 1; // will NOT affect original } var object1 = { prop: "car" }; var object2 = { prop: "bike" }; var number1 = 10; passVar(object1, object2, number1); console.log(object1); //output: Object {item:"laptop"} console.log(object2); //output: Object {item:"bike"} console.log(number1); //ouput: 10 

Soluzione alternativa per passare una variabile come per riferimento:

 var a = 1; inc = function(variableName) { window[variableName] += 1; }; inc('a'); alert(a); // 2 

MODIFICARE

sì, in realtà puoi farlo senza accesso globale

 inc = (function () { var variableName = 0; var init = function () { variableName += 1; alert(variableName); } return init; })(); inc(); 

Oggetto semplice

 var ref = { value: 1 }; function Foo(x) { x.value++; } Foo(ref); Foo(ref); alert(ref.value); // Alert: 3 

Oggetto personalizzato

Oggetto rvar

 function rvar (name, value, context) { if (this instanceof rvar) { this.value = value; Object.defineProperty(this, 'name', { value: name }); Object.defineProperty(this, 'hasValue', { get: function () { return this.value !== undefined; } }); if ((value !== undefined) && (value !== null)) this.constructor = value.constructor; this.toString = function () { return this.value + ''; }; } else { if (!rvar.refs) rvar.refs = {}; if (!context) context = window; // Private rvar.refs[name] = new rvar(name, value); // Public Object.defineProperty(context, name, { get: function () { return rvar.refs[name]; }, set: function (v) { rvar.refs[name].value = v; }, configurable: true }); return context[name]; } } 

Dichiarazione variabile

 rvar('test_ref'); test_ref = 5; // test_ref.value = 5 

O:

 rvar('test_ref', 5); // test_ref.value = 5 

Codice di prova

 rvar('test_ref_number'); test_ref_number = 5; function Fn1 (v) { v.value = 100; } console.log("rvar('test_ref_number');"); console.log("test_ref_number = 5;"); console.log("function Fn1 (v) { v.value = 100; }"); console.log('test_ref_number.value === 5', test_ref_number.value === 5); console.log(" "); Fn1(test_ref_number); console.log("Fn1(test_ref_number);"); console.log('test_ref_number.value === 100', test_ref_number.value === 100); console.log(" "); test_ref_number++; console.log("test_ref_number++;"); console.log('test_ref_number.value === 101', test_ref_number.value === 101); console.log(" "); test_ref_number = test_ref_number - 10; console.log("test_ref_number = test_ref_number - 10;"); console.log('test_ref_number.value === 91', test_ref_number.value === 91); console.log(" "); console.log("---------"); console.log(" "); rvar('test_ref_str', 'a'); console.log("rvar('test_ref_str', 'a');"); console.log('test_ref_str.value === "a"', test_ref_str.value === 'a'); console.log(" "); test_ref_str += 'bc'; console.log("test_ref_str += 'bc';"); console.log('test_ref_str.value === "abc"', test_ref_str.value === 'abc'); 

Risultato della console di test

 rvar('test_ref_number'); test_ref_number = 5; function Fn1 (v) { v.value = 100; } test_ref_number.value === 5 true Fn1(test_ref_number); test_ref_number.value === 100 true test_ref_number++; test_ref_number.value === 101 true test_ref_number = test_ref_number - 10; test_ref_number.value === 91 true --------- rvar('test_ref_str', 'a'); test_ref_str.value === "a" true test_ref_str += 'bc'; test_ref_str.value === "abc" true 

Un altro approccio per passare qualsiasi variabile (locale, primitiva) per riferimento è la variabile wrapping con chiusura “al volo” di eval . Funziona anche con “use strict”. (Nota: essere consapevoli che eval non è amichevole con gli ottimizzatori JS, anche le virgolette mancanti attorno al nome della variabile possono causare risultati imprevedibili)

 "use strict" //return text that will reference variable by name (by capturing that variable to closure) function byRef(varName){ return "({get value(){return "+varName+";}, set value(v){"+varName+"=v;}})"; } //demo //assign argument by reference function modifyArgument(argRef, multiplier){ argRef.value = argRef.value * multiplier; } (function(){ var x = 10; alert("x before: " + x); modifyArgument(eval(byRef("x")), 42); alert("x after: " + x); })() 

Esempio dal vivo https://jsfiddle.net/t3k4403w/

Ho giocato con la syntax per fare questo genere di cose, ma richiede alcuni aiutanti che sono un po ‘insoliti. Inizia senza usare “var”, ma un semplice helper “DECLARE” che crea una variabile locale e ne definisce uno scope tramite un callback anonimo. Controllando il modo in cui le variabili vengono dichiarate, possiamo scegliere di includerle in oggetti in modo che possano essere sempre passati per riferimento, in sostanza. Questo è simile a una delle risposte di Eduardo Cuomo sopra, ma la soluzione seguente non richiede l’uso di stringhe come identificatori di variabili. Ecco un codice minimale per mostrare il concetto.

 function Wrapper(val){ this.VAL = val; } Wrapper.prototype.toString = function(){ return this.VAL.toString(); } function DECLARE(val, callback){ var valWrapped = new Wrapper(val); callback(valWrapped); } function INC(ref){ if(ref && ref.hasOwnProperty('VAL')){ ref.VAL++; } else{ ref++;//or maybe throw here instead? } return ref; } DECLARE(5, function(five){ //consider this line the same as 'let five = 5' console.log("five is now " + five); INC(five); // increment console.log("five is incremented to " + five); }); 

In realtà c’è un bel sollution:

 function updateArray(context, targetName, callback) { context[targetName] = context[targetName].map(callback); } var myArray = ['a', 'b', 'c']; updateArray(this, 'myArray', item => {return '_' + item}); console.log(myArray); //(3) ["_a", "_b", "_c"] 

in realtà è davvero facile,

il problema è capire che una volta passati gli argomenti classici, si è circoscritti in un’altra zona di sola lettura.

soluzioni è passare gli argomenti usando la progettazione orientata agli oggetti di JavaScript,

è come mettere gli arg in una variabile globale / con scope, ma meglio …

 function action(){ /* process this.arg, modification allowed */ } action.arg = [ ["empty-array"],"some string",0x100,"last argument" ]; action(); 

puoi anche prometterti roba per goderti la ben nota catena: ecco il tutto, con una struttura promettente

 function action(){ /* process this.arg, modification allowed */ this.arg = ["a","b"]; } action.setArg = function(){this.arg = arguments; return this;} action.setArg(["empty-array"],"some string",0x100,"last argument")() 

o meglio ancora .. action.setArg(["empty-array"],"some string",0x100,"last argument").call()

Personalmente non mi piace la funzionalità “passa per riferimento” offerta da vari linguaggi di programmazione. Forse perché sto solo scoprendo i concetti di programmazione funzionale, ma ho sempre la pelle d’oca quando vedo le funzioni che causano effetti collaterali (come la manipolazione dei parametri passati per riferimento). Personalmente abarm fortemente il principio della “responsabilità unica”.

IMHO, una funzione dovrebbe restituire solo un risultato / valore usando la parola chiave return. Invece di modificare un parametro / argomento, vorrei solo restituire il valore modificato parametro / argomento e lasciare qualsiasi riassegnazione desiderata fino al codice chiamante.

Ma a volte (si spera molto raramente), è necessario restituire due o più valori di risultato dalla stessa funzione. In tal caso, sceglierei di includere tutti quei valori risultanti in una singola struttura o object. Anche in questo caso, l’elaborazione di eventuali riassegnazioni deve essere eseguita fino al codice di chiamata.

Esempio:

Supponiamo che i parametri di passaggio siano supportati utilizzando una parola chiave speciale come “ref” nella lista degli argomenti. Il mio codice potrebbe essere simile a questo:

 //The Function function doSomething(ref value) { value = "Bar"; } //The Calling Code var value = "Foo"; doSomething(value); console.log(value); //Bar 

Invece, in realtà preferirei fare qualcosa del genere:

 //The Function function doSomething(value) { value = "Bar"; return value; } //The Calling Code: var value = "Foo"; value = doSomething(value); //Reassignment console.log(value); //Bar 

Quando avrei bisogno di scrivere una funzione che restituisce più valori, non utilizzerei neanche i parametri passati per riferimento. Quindi eviterei codice come questo:

 //The Function function doSomething(ref value) { value = "Bar"; //Do other work var otherValue = "Something else"; return otherValue; } //The Calling Code var value = "Foo"; var otherValue = doSomething(value); console.log(value); //Bar console.log(otherValue); //Something else 

Invece, in realtà preferirei restituire entrambi i nuovi valori all’interno di un object, come questo:

 //The Function function doSomething(value) { value = "Bar"; //Do more work var otherValue = "Something else"; return { value: value, otherValue: otherValue }; } //The Calling Code: var value = "Foo"; var result = doSomething(value); value = result.value; //Reassignment console.log(value); //Bar console.log(result.otherValue); 

Questi esempi di codice sono abbastanza semplici, ma dimostrano approssimativamente come personalmente gestirò tali cose. Mi aiuta a mantenere varie responsabilità nel posto giusto.

Buona programmazione. 🙂

So esattamente cosa intendi. La stessa cosa in Swift non sarà un problema. La linea di fondo è usare non let var .

Il fatto che i primitivi siano passati per valore ma il fatto che il valore di var i nel punto di iterazione non sia copiato nella funzione anonima è abbastanza sorprendente, per non dire altro.

 for (let i = 0; i < boxArray.length; i++) { boxArray[i].onclick = function() { console.log(i) }; // correctly prints the index }