Cum pot trece variabile de referință în JavaScript? Am 3 variabile pe care nu doriți să efectuați mai multe operațiuni, așa că vreau să le-a pus într-o buclă și de a efectua operațiuni pentru fiecare în parte.
pseudo-codul:
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
Ceea ce este cel mai bun mod de a face acest lucru?
Nu există nici o "trece de referință" disponibil în JavaScript. Puteți trece un obiect (care este de a spune, puteți trece-de-valoare o referință la un obiect) și apoi au o funcție modifica obiectul cuprins:
function alterObject(obj) {
obj.foo = "goodbye";
}
var myObj = { foo: "hello world" };
alterObject(myObj);
alert(myObj.foo); // "goodbye" instead of "hello world"
Puteți repeta peste proprietățile unei matrice cu un index numeric și modifica fiecare celulă din matrice, dacă doriți.
var arr = [1, 2, 3];
for (var i = 0; i < arr.length; i++) {
arr[i] = arr[i] + 1;
}
L's important să rețineți că "trece-prin-trimitere" este un termen specific. Aceasta nu înseamnă pur și simplu că-l's posibil pentru a trece o referință la un obiect modificabil. În schimb, înseamnă că-l's posibil pentru a trece o simplă variabilă în așa fel încât să permită o funcție pentru a modifica această valoare în asteptare contextul. Deci:
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"
Într-un limbaj ca C++, l's posibil pentru a face asta, pentru că limba nu (tip-a) au trecut de referință.
edit — acest recent (Martie 2015) a explodat pe Reddit din nou peste un blog post similar cu al meu menționate mai jos, deși, în acest caz, despre Java. Aceasta a avut loc pentru mine în timp ce citesc back-și-mai departe în Reddit comentarii că o mare parte din confuzia provine din la nefericita coliziune implică cuvântul "de referință". Terminologia "trece de referință" și "trece prin valoarea" precede conceptul de a avea "obiecte" pentru a lucra cu în limbaje de programare. L's nu despre obiecte, la toate; it's despre parametrii de funcționare, și în special modul în parametrii funcției sunt "conectat" (sau nu) la chemarea mediu. În special, rețineți că într-un adevărat trece-prin referire limba — un ca nu implica obiecte — s-ar putea încă mai au capacitatea de a modifica obiect cuprins, și ar arăta destul de mult exact ca în JavaScript. Cu toate acestea, ar de asemenea să fie capabil de a modifica obiectul de referință în mediul apelant, și că's cel mai important lucru care le poate't fac în JavaScript. O trecere-prin-trimitere limba ar nu treci de referință în sine, ci un de referință de referință.
edit — aici este un post pe blog pe acest subiect. (Nota comentariu la acest post care explică faptul că C++ nu't chiar trebuie să treacă de referință. Că este adevărat. Ce C++ are, cu toate acestea, este abilitatea de a crea referințe la câmpie variabile, fie în mod explicit la punctul de funcția de invocare a crea un pointer, sau implicit atunci când apelează funcții al căror argument de tip semnătura solicită ca să fie făcut. Acestea sunt cele mai importante lucruri de activarea JavaScript-nu't de suport.)
object1 = {prop: "auto"}; array1 = [1,2,3];
object1.prop = "auto"; array1[0] = 9;
Cod
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
Soluție pentru a trece de variabile cum ar fi de referință:
var a = 1;
inc = function(variableName) {
window[variableName] += 1;
};
inc('a');
alert(a); // 2
EDIT
da, de fapt, o poți face fără acces global
inc = (function () {
var variableName = 0;
var init = function () {
variableName += 1;
alert(variableName);
}
return init;
})();
inc();
var ref = { value: 1 };
function Foo(x) {
x.value++;
}
Foo(ref);
Foo(ref);
alert(ref.value); // Alert: 3
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];
}
}
rvar('test_ref');
test_ref = 5; // test_ref.value = 5
Sau:
rvar('test_ref', 5); // test_ref.value = 5
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');
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
O altă abordare pentru a trece orice (locale, primitive) variabile de referință este de ambalaj variabilă cu închidere "pe zbor" de "eval". Acest lucru, de asemenea, funcționează cu "de utilizare strict". (Notă: fiți conștienți de faptul că "eval" nu este prietenos cu JS optimizatori, de asemenea, lipsesc ghilimele numele variabilei poate provoca unpredictive rezultate)
"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);
})()
Live proba
Am'am jucat în jurul cu sintaxa pentru a face acest tip de lucru, dar este nevoie de unele ajutoare care sunt un pic neobișnuit. Acesta începe cu a nu utiliza 'var' la toate, dar un simplu 'DECLARA' helper care creează o variabilă locală și definește domeniul de aplicare de acesta printr-un anonim de apel invers. Prin controlul cât de variabile sunt declarate, putem alege să le înveliți în obiecte, astfel încât acestea pot fi întotdeauna transmis prin referință, în esență. Acest lucru este similar cu unul de Eduardo Cuomo's răspunsul de mai sus, dar solutia de mai jos nu are nevoie de ajutorul siruri de caractere ca variabilă de identificare. Aici's un minim de cod pentru a arăta concept.
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);
});
Nu's de fapt o destul de solutie:
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"]
Eu personal mi place "trece de referință" funcționalitate oferite de catre diverse limbaje de programare. Poate că's pentru că eu sunt doar descoperi concepte de programare funcțională, dar mereu mi se face pielea de găină când am văzut funcții care cauzeaza efecte secundare (cum ar fi manipularea parametri transmiși prin referință). Eu personal puternic îmbrățișeze "singură responsabilitate" principiul.
IMHO, o funcție ar trebui să revină doar un singur rezultat/valoarea cu ajutorul reveni cuvinte cheie. În loc de a modifica un parametru/argument, aș reveni modificat parametru/valoare argument și lăsa de dorit mutarea până la codul de asteptare.
Dar, uneori, (să sperăm că foarte rar), este necesar să se întoarcă de două sau mai multe valori rezultat din aceeași funcție. În acest caz, eu as opta pentru a include toate cele care rezultă valori într-o singură structură sau un obiect. Din nou, prelucrarea orice mutarea ar trebui să fie de până la codul de asteptare.
Exemplu:
Să presupunem că trece parametrii ar fi sprijinite prin utilizarea unui cuvânt cheie special ca 'ref' în lista de argumente. Codul meu s-ar putea arata ceva de genul asta:
//The Function
function doSomething(ref value) {
value = "Bar";
}
//The Calling Code
var value = "Foo";
doSomething(value);
console.log(value); //Bar
În schimb, de fapt aș prefera să fac ceva de genul asta:
//The Function
function doSomething(value) {
value = "Bar";
return value;
}
//The Calling Code:
var value = "Foo";
value = doSomething(value); //Reassignment
console.log(value); //Bar
Când am nevoie pentru a scrie o functie care returneaza mai multe valori, nu aș folosi parametri transmiși prin referință, fie. Deci, mi-ar evita ca acest cod:
//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
În schimb, de fapt aș prefera să se întoarcă ambele valori noi în interiorul unui obiect, astfel:
//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);
Aceste exemple de cod sunt destul de simplificată, dar aproximativ demonstrează cum eu, personal, s-ar ocupa de astfel de lucruri. Ajută-mă să păstreze diverse responsabilități în locul corect.
Fericit de codificare. :)
function action(){
/* process this.arg, modification allowed */
}
action.arg = [ ["empty-array"],"some string",0x100,"last argument" ];
action();
puteți, de asemenea, promit lucrurile să bucurați-vă de bine-cunoscut lanț: aici este totul, cu promit ca structura
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")()
sau mai bine.. acțiune.setArg(["gol-matrice"],"un string",0x100,"ultimul argument").apel()`
Știu exact ce vrei să spui. Același lucru în Swift va fi nici o problemă.
Linia de jos este utilizat sa
nu var
.
Faptul că primitive sunt transmise prin valoare, dar faptul că valoarea de var i` la punctul de repetare nu este copiat în funcție anonim este destul de surprinzător pentru a spune cel mai puțin.
for (let i = 0; i < boxArray.length; i++) {
boxArray[i].onclick = function() { console.log(i) }; // correctly prints the index
}
Javascript poate modifica serie de elemente în interiorul unei funcții (este trecut ca o referință la obiectul/matrice).
function makeAllPretty(items) {
for (var x = 0; x < myArray.length; x++){
//do stuff to the array
items[x] = makePretty(items[x]);
}
}
myArray = new Array(var1, var2, var3);
makeAllPretty(myArray);
Aici's un alt exemplu:
function inc(items) {
for (let i=0; i < items.length; i++) {
items[i]++;
}
}
let values = [1,2,3];
inc(values);
console.log(values);
// prints [2,3,4]
JS nu sunt de tip puternic, care vă permite pentru a rezolva probleme în mai multe moduri diferite, cum pare în acest benzii de rulare.
Cu toate acestea, pentru mentenabilitatea punct de vedere, nu ar trebui să fie de acord cu Bart Hofland. Funcția ar trebui să args de a face ceva cu și să se întoarcă rezultatul. Ceea ce le face ușor de unică folosință.
Dacă vă simțiți că variabilele trebuie să fie transmis prin referință poate fi mai bine servite Construirea lor în obiecte IMHO.