it-swarm.com.de

Übergeben Sie Variablen als Referenz in Javascript

Wie übergebe ich Variablen als Referenz in JS? Ich habe 3 Variablen, für die ich mehrere Operationen ausführen möchte, also möchte ich sie in eine for-Schleife schreiben und die Operationen für jede einzelne ausführen.

pseudo-Code:

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

Was ist der beste Weg, dies zu tun?

243
BFTrick

In JavaScript ist kein "Referenzzugriff" verfügbar. Sie können ein Objekt übergeben (dh Sie können einen Verweis auf ein Objekt übergeben) und dann den Objektinhalt mit einer Funktion ändern lassen:

function alterObject(obj) {
  obj.foo = "goodbye";
}

var myObj = { foo: "hello world" };

alterObject(myObj);

alert(myObj.foo); // "goodbye" instead of "hello world"

Nun, in Ihrem Fall übergeben Sie sowieso nichts, soweit ich das beurteilen kann. Sie können die Eigenschaften eines Arrays mit einem numerischen Index durchlaufen und jede Zelle des Arrays ändern, wenn Sie möchten.

Es ist wichtig zu wissen, dass "Referenzübergabe" ein sehr spezifischer Begriff ist. Das bedeutet nicht einfach, dass es möglich ist, einen Verweis auf ein modifizierbares Objekt zu übergeben. Stattdessen bedeutet dies, dass es möglich ist, eine einfache Variable so zu übergeben, dass eine Funktion diesen Wert im Kontext aufrufende ändern kann. So:

 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 einer Sprache wie C++ ist dies möglich, da diese Sprache do (sort-of) über Referenzzugriff verfügt.

edit - Dies ist kürzlich (März 2015) in Reddit erneut über einen ähnlichen Blogbeitrag gesprungen, der meinem ähnlich ist, der in diesem Artikel erwähnt wird, allerdings in diesem Fall über Java. Beim Lesen des Hin und Her in den Reddit-Kommentaren fiel mir ein, dass ein großer Teil der Verwirrung auf die unglückliche Kollision mit dem Wort "Referenz" zurückzuführen ist. Die Terminologie "Referenz übergeben" und "Wert übergeben" geht dem Konzept voraus, dass "Objekte" in Programmiersprachen verwendet werden. Es geht wirklich gar nicht um Objekte. es geht um Funktionsparameter und insbesondere darum, wie Funktionsparameter mit der aufrufenden Umgebung "verbunden" sind (oder nicht). Beachten Sie insbesondere, dass in einer echten Referenz-Referenzsprache - einer, die tut Objekte umfasst - man immer noch die Möglichkeit hat, das Objekt Inhalt zu ändern, und es sieht ziemlich gut aus genau wie in JavaScript. Man könnte jedoch auch die Objektreferenz in der aufrufenden Umgebung ändern, und dies ist der Schlüssel, den Sie in JavaScript nicht tun können. Eine Referenz-Referenzsprache würde nicht die Referenz selbst übergeben, sondern ein Referenz auf die Referenz.

edit - Hier ist ein Blogbeitrag zum Thema. (Beachten Sie den Kommentar zu diesem Beitrag, in dem erklärt wird, dass C++ nicht wirklich über Pass-by-Reference verfügt. Das ist wahr. Was C++ jedoch bietet, ist die Möglichkeit, Verweise auf einfache Variablen zu erstellen, entweder explizit an diesem Punkt Aufruf der Funktion zum Erstellen eines Zeigers oder implizit beim Aufruf von Funktionen, deren Unterschrift des Argumenttyps dazu erforderlich ist. Dies sind die Schlüsselfaktoren, die JavaScript nicht unterstützt.)

356
Pointy
  1. primitive Typvariablen wie Strings und Zahlen werden immer als Wert übergeben.
  2. Arrays und Objekte werden aufgrund dieser Bedingungen als Referenz oder als Wert übergeben:

    • wenn Sie den Wert eines Objekts oder Arrays festlegen, ist dies die Option Nach Wert übergeben.

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

    • wenn Sie einen Eigenschaftswert eines Objekts oder Arrays ändern, wird dies als Referenz übergeben.

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

Code

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

85
Mukund Kumar

Problemumgehung zum Übergeben der Variablen als Referenz:

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

inc('a');

alert(a); // 2


EDIT

yup, eigentlich können Sie es ohne Zugriff global tun

inc = (function () {
    var variableName = 0;

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

    return init;
})();

inc();
22
user2410595

Einfaches Objekt

var ref = { value: 1 };

function Foo(x) {
    x.value++;
}

Foo(ref);
Foo(ref);

alert(ref.value); // Alert: 3

Benutzerdefiniertes Objekt

Objekt 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];
    }
}

Variable Aussage

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

Oder:

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

Testcode

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');

Ergebnis der Testkonsole

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 
10
Eduardo Cuomo

Ein weiterer Ansatz, um (lokale, primitive) Variablen per Referenz zu übergeben, besteht darin, die Variable mit eval "on the fly" zu schließen. Dies funktioniert auch mit "use strict". (Hinweis: Beachten Sie, dass eval nicht für JS-Optimierer geeignet ist. Auch fehlende Anführungszeichen um den Variablennamen können zu unvorhersehbaren Ergebnissen führen.)

"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-Beispiel https://jsfiddle.net/t3k4403w/

5
Pavlo Mur

Es gibt eigentlich eine hübsche Lösung:

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"]
2
Mateus Araújo

Ich habe mit Syntax herumgespielt, um so etwas zu tun, aber es erfordert einige Helfer, die etwas ungewöhnlich sind. Es beginnt damit, dass 'var' überhaupt nicht verwendet wird, sondern ein einfacher 'DECLARE'-Helfer, der eine lokale Variable erstellt und über einen anonymen Rückruf einen Gültigkeitsbereich definiert. Indem wir kontrollieren, wie Variablen deklariert werden, können wir sie in Objekte einschließen, sodass sie im Wesentlichen immer als Referenz übergeben werden können. Dies ist ähnlich einer Antwort von Eduardo Cuomo oben, aber für die Lösung unten müssen keine Strings als variable Bezeichner verwendet werden. Hier ist minimaler Code, um das Konzept zu zeigen.

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);
});
2
Adam Wise

eigentlich ist es wirklich einfach,

das Problem besteht darin, zu verstehen, dass Sie nach der Übergabe klassischer Argumente in eine andere schreibgeschützte Zone weitergeleitet werden.

die Lösung besteht darin, die Argumente mithilfe des objektorientierten Designs von JavaScript zu übergeben.

es ist dasselbe wie das Einfügen der Argumente in eine globale Variable mit Gültigkeitsbereich, aber besser ...

function action(){
  /* process this.arg, modification allowed */
}

action.arg = [ ["empty-array"],"some string",0x100,"last argument" ];
action();

sie können auch versprechen Sachen zu machen, um die bekannte Kette zu genießen: Hier ist das Ganze mit versprechensartige Struktur

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")()

oder noch besser .. action.setArg(["empty-array"],"some string",0x100,"last argument").call()

1
user257319

Ich persönlich mag die "Pass by Reference" -Funktionalität, die von verschiedenen Programmiersprachen angeboten wird, nicht. Vielleicht liegt es daran, dass ich gerade die Konzepte der funktionalen Programmierung entdecke, aber ich bekomme immer Gänsehaut, wenn ich Funktionen sehe, die Nebenwirkungen verursachen (wie das Verändern von Parametern, die als Referenz übergeben werden). Ich persönlich befürworte ausdrücklich das Prinzip der "Einzelverantwortung".

IMHO sollte eine Funktion mit dem Schlüsselwort return nur ein Ergebnis/einen Wert zurückgeben. Anstatt einen Parameter/ein Argument zu ändern, würde ich einfach den geänderten Parameter/Argumentwert zurückgeben und die gewünschten Neuzuweisungen dem aufrufenden Code überlassen.

Manchmal (hoffentlich sehr selten) müssen jedoch zwei oder mehr Ergebniswerte aus derselben Funktion zurückgegeben werden. In diesem Fall würde ich mich dazu entscheiden, alle resultierenden Werte in einer einzelnen Struktur oder einem einzelnen Objekt zu verwenden. Auch hier sollte die Verarbeitung von Neuzuordnungen dem aufrufenden Code entsprechen.

Beispiel:

Angenommen, das Übergeben von Parametern würde durch Verwendung eines speziellen Schlüsselworts wie 'ref' in der Argumentliste unterstützt. Mein Code könnte ungefähr so ​​aussehen:

//The Function
function doSomething(ref value) {
    value = "Bar";
}

//The Calling Code
var value = "Foo";
doSomething(value);
console.log(value); //Bar

Stattdessen würde ich lieber so etwas machen:

//The Function
function doSomething(value) {
    value = "Bar";
    return value;
}

//The Calling Code:
var value = "Foo";
value = doSomething(value); //Reassignment
console.log(value); //Bar

Wenn ich eine Funktion schreiben müsste, die mehrere Werte zurückgibt, würde ich auch keine als Referenz übergebenen Parameter verwenden. Ich würde also folgenden Code vermeiden:

//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

Stattdessen würde ich es vorziehen, beide neuen Werte wie folgt in einem Objekt zurückzugeben:

//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);

Diese Codebeispiele sind ziemlich vereinfacht, aber es zeigt grob, wie ich persönlich damit umgehen würde. Es hilft mir, verschiedene Verantwortlichkeiten an der richtigen Stelle zu halten.

Glückliche Kodierung :)

1
Bart Hofland

Abgesehen von der Pass-by-Reference-Diskussion könnten diejenigen, die noch nach einer Lösung für die angegebene Frage suchen, Folgendes verwenden:

const myArray = new Array(var1, var2, var3);
myArray.forEach(var => var = makePretty(var));
0
Shira Joseph

Ich weiß genau was du meinst. Das Gleiche ist in Swift kein Problem. Die untere Zeile ist let und nicht var.

Die Tatsache, dass Primitive per Wert übergeben werden, aber der Wert von var i am Punkt der Iteration nicht in die anonyme Funktion kopiert wird, ist zumindest überraschend.

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

Da JS kein starker Typ ist, können Sie Probleme auf viele verschiedene Arten lösen, wie dies in diesem Profil der Fall ist.

Aus Sicht der Wartbarkeit müsste ich jedoch Bart Hofland zustimmen. Die Funktion sollte Argumente dazu bringen, etwas zu tun und das Ergebnis zurückzugeben. Sie sind leicht wiederverwendbar. 

Wenn Sie der Meinung sind, dass Variablen als Referenz übergeben werden müssen, ist es möglicherweise besser, sie in Objekte IMHO zu integrieren.

0
Michel S

Javascript kann Array-Elemente innerhalb einer Funktion ändern (sie werden als Referenz an das Objekt/Array übergeben).

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);

Hier ist ein anderes Beispiel:

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]