在 Javascript 中通过引用传递变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7744611/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 03:25:27  来源:igfitidea点击:

Pass Variables by Reference in Javascript

javascriptvariablespass-by-reference

提问by BFTrick

How do I pass variables by reference in JavaScript? I have 3 variables that I want to perform several operations to, so I want to put them in a for loop and perform the operations to each one.

如何在 JavaScript 中通过引用传递变量?我有 3 个变量要对其执行多个操作,因此我想将它们放入 for 循环中并对每个变量执行操作。

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

What is the best way to do this?

做这个的最好方式是什么?

回答by Pointy

There is no "pass by reference" available in JavaScript. You can pass an object (which is to say, you can pass-by-value a reference to an object) and then have a function modify the object contents:

JavaScript 中没有可用的“通过引用传递”。您可以传递一个对象(也就是说,您可以按值传递对对象的引用),然后让函数修改对象内容:

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

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

alterObject(myObj);

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

You can iterate over the properties of an array with a numeric index and modify each cell of the array, if you want.

如果需要,您可以使用数字索引迭代数组的属性并修改数组的每个单元格。

var arr = [1, 2, 3];

for (var i = 0; i < arr.length; i++) { 
    arr[i] = arr[i] + 1; 
}

It's important to note that "pass-by-reference" is a very specific term. It does not mean simply that it's possible to pass a reference to a modifiable object. Instead, it means that it's possible to pass a simple variable in such a way as to allow a function to modify that value in the callingcontext. 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 a language like C++, it's possible to do that because that language does(sort-of) have pass-by-reference.

在像 C++ 这样的语言中,可以这样做,因为该语言确实(排序)具有按引用传递。

edit— this recently (March 2015) blew up on Reddit again over a blog post similar to mine mentioned below, though in this case about Java. It occurred to me while reading the back-and-forth in the Reddit comments that a big part of the confusion stems from the unfortunate collision involving the word "reference". The terminology "pass by reference" and "pass by value" predates the concept of having "objects" to work with in programming languages. It's really not about objects at all; it's about function parameters, and specifically how function parameters are "connected" (or not) to the calling environment. In particular, note that in a true pass-by-reference language — one that doesinvolve objects — one would still have the ability to modify object contents, and it would look pretty much exactly like it does in JavaScript. However, one would alsobe able to modify the object reference in the calling environment, and that's the key thing that you can'tdo in JavaScript. A pass-by-reference language would pass not the reference itself, but a reference to the reference.

编辑- 最近(2015 年 3 月)在 Reddit 上再次通过一篇类似于下面提到的我的博客文章炸毁了它,尽管在这种情况下是关于 Java。我在阅读 Reddit 评论中的来回评论时突然想到,很大一部分混乱源于涉及“引用”一词的不幸冲突。术语“通过引用传递”和“通过值传递”早于在编程语言中使用“对象”的概念。这真的与对象无关。它是关于函数参数,特别是函数参数如何“连接”(或不连接)到调用环境。特别是,,它看起来与 JavaScript 中的非常相似。但是,您可以在调用环境中修改对象引用,这是您在 JavaScript 中无法做到的关键。传递引用语言不会传递引用本身,而是传递对引用的引用

edithere is a blog post on the topic.(Note the comment to that post that explains that C++ doesn't really have pass-by-reference. That is true. What C++ does have, however, is the ability to create references to plain variables, either explicitly at the point of function invocation to create a pointer, or implicitlywhen calling functions whose argument type signature calls for that to be done. Those are the key things JavaScript doesn't support.)

编辑-这是关于该主题的博客文章。(请注意那篇文章的评论,它解释了 C++ 并没有真正通过引用传递。这是真的。然而,C++ 确实具有创建对普通变量的引用的能力,或者在函数点显式调用以创建指针,或在调用其参数类型签名要求完成的函数时隐式调用。这些是 JavaScript 不支持的关键内容。)

回答by Mukund Kumar

  1. primitive type variables like strings and numbers are always passed by value.
  2. Arrays and Objects are passed by reference or by value based on these conditions:

    • if you are setting the value of an object or array it is Pass by Value.

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

    • if you are changing a property value of an object or array then it is Pass by Reference.

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

  1. 像字符串和数字这样的原始类型变量总是按值传递。
  2. 数组和对象根据以下条件按引用或按值传递:

    • 如果您要设置对象或数组的值,则它是按值传递。

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

    • 如果您要更改对象或数组的属性值,则它是按引用传递。

      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

回答by user2410595

Workaround to pass variable like by reference:

通过引用传递变量的解决方法:

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

inc('a');

alert(a); // 2


EDIT


编辑

yup, actually you can do it without access global

是的,实际上你可以在没有访问全局的情况下做到这一点

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

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

    return init;
})();

inc();

回答by Eduardo Cuomo

Simple Object

简单对象

var ref = { value: 1 };

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

Foo(ref);
Foo(ref);

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


Custom Object

自定义对象

Object rvar

目的 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 Declaration

变量声明

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

Or:

或者:

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

Test Code

测试代码

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

Test Console Result

测试控制台结果

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 

回答by Pavlo Mur

Yet another approach to pass any (local, primitive) variables by reference is by wrapping variable with closure "on the fly" by eval. This also works with "use strict". (Note: be aware that evalis not friendly to JS optimizers, also missing quotes around variable name may cause unpredictive results)

另一种通过引用传递任何(本地、原始)变量的方法是通过eval. 这也适用于“使用严格”。(注意:注意这eval对 JS 优化器不友好,变量名周围缺少引号可能会导致不可预测的结果)

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

实时示例https://jsfiddle.net/t3k4403w/

回答by Mateus Araújo

There's actually a pretty 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"]

回答by Bart Hofland

I personally dislike the "pass by reference" functionality offered by various programming languages. Perhaps that's because I am just discovering the concepts of functional programming, but I always get goosebumps when I see functions that cause side effects (like manipulating parameters passed by reference). I personally strongly embrace the "single responsibility" principle.

我个人不喜欢各种编程语言提供的“通过引用传递”功能。也许那是因为我刚刚发现函数式编程的概念,但是当我看到会引起副作用的函数(例如操作通过引用传递的参数)时,我总是起鸡皮疙瘩。我个人强烈拥护“单一责任”原则。

IMHO, a function should return just one result/value using the return keyword. Instead of modifying a parameter/argument, I would just return the modified parameter/argument value and leave any desired reassignments up to the calling code.

恕我直言,一个函数应该使用 return 关键字只返回一个结果/值。我不会修改参数/参数,而是返回修改后的参数/参数值,并将任何所需的重新分配留给调用代码。

But sometimes (hopefully very rarely), it is necessary to return two or more result values from the same function. In that case, I would opt to include all those resulting values in a single structure or object. Again, processing any reassignments should be up to the calling code.

但有时(希望很少),有必要从同一个函数返回两个或多个结果值。在这种情况下,我会选择将所有这些结果值包含在单个结构或对象中。同样,处理任何重新分配应该由调用代码决定。

Example:

例子:

Suppose passing parameters would be supported by using a special keyword like 'ref' in the argument list. My code might look something like this:

假设通过在参数列表中使用像“ref”这样的特殊关键字来支持传递参数。我的代码可能如下所示:

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

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

Instead, I would actually prefer to do something like this:

相反,我实际上更愿意做这样的事情:

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

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

When I would need to write a function that returns multiple values, I would not use parameters passed by reference either. So I would avoid code like this:

当我需要编写一个返回多个值的函数时,我也不会使用通过引用传递的参数。所以我会避免这样的代码:

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

Instead, I would actually prefer to return both new values inside an object, like this:

相反,我实际上更喜欢在对象内返回两个新值,如下所示:

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

These code examples are quite simplified, but it roughly demonstrates how I personally would handle such stuff. It helps me to keep various responsibilities in the correct place.

这些代码示例相当简化,但它粗略地展示了我个人将如何处理这些东西。它帮助我将各种责任放在正确的位置。

Happy coding. :)

快乐编码。:)

回答by Adam Wise

I've been playing around with syntax to do this sort of thing, but it requires some helpers that are a little unusual. It starts with not using 'var' at all, but a simple 'DECLARE' helper that creates a local variable and defines a scope for it via an anonymous callback. By controlling how variables are declared, we can choose to wrap them into objects so that they can always be passed by reference, essentially. This is similar to one of the Eduardo Cuomo's answer above, but the solution below does not require using strings as variable identifiers. Here's some minimal code to show the concept.

我一直在玩弄语法来做这种事情,但它需要一些有点不寻常的助手。它从根本不使用“var”开始,而是一个简单的“DECLARE”助手,它创建一个局部变量并通过匿名回调为其定义一个范围。通过控制变量的声明方式,我们可以选择将它们包装成对象,以便它们本质上始终可以通过引用传递。这类似于上面 Eduardo Cuomo 的答案之一,但下面的解决方案不需要使用字符串作为变量标识符。这里有一些最小的代码来展示这个概念。

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

回答by Adam Wise

actually it is really easy,

其实很简单,

the problem is understanding that once passing classic arguments, you are scoped into another, read-only zone.

问题在于,一旦传递经典参数,您就会被限制在另一个只读区域中。

solutions is to pass the arguments using JavaScript's object-oriented design,

解决方案是使用 JavaScript 的面向对象设计传递参数,

it is the same as putting the args in a global/scoped variable, but better...

它与将 args 放在全局/范围变量中相同,但更好......

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

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

you can also promisestuff up to enjoy the well-known chain: here is the whole thing, with promise-like structure

您还可以承诺享受众所周知的连锁店的东西:这是整个事情,具有类似承诺的结构

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

or better yet.. action.setArg(["empty-array"],"some string",0x100,"last argument").call()

或者更好.. action.setArg(["empty-array"],"some string",0x100,"last argument").call()

回答by funct7

I know exactly what you mean. Same thing in Swift will be no problem. Bottom line is use letnot var.

我确切地知道你的意思。同样的事情在 Swift 中也没有问题。底线是let不使用var

The fact that primitives are passed by value but the fact that the value of var iat the point of iteration is not copied into the anonymous function is quite surprising to say the least.

原语是按值传递的,但var i迭代点的值没有复制到匿名函数中这一事实至少可以说是相当令人惊讶的。

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