如何在JavaScript中通过引用传递变量?

我有三个变量,我想对它们执行一些操作,所以我想把它们放在一个for循环中,并对每个变量执行操作。

伪代码:

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 variables

最好的方法是什么?


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

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

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

alterObject(myObj);

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

如果需要,可以使用数值索引遍历数组的属性,并修改数组的每个单元格。

var arr = [1, 2, 3];

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

需要注意的是,“引用传递”是一个非常具体的术语。这并不仅仅意味着可以将引用传递给一个可修改的对象。相反,这意味着可以通过允许函数在调用上下文中修改该值的方式传递简单变量。所以:

 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"

在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 does involve 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 also be able to modify the object reference in the calling environment, and that's the key thing that you can't do in JavaScript. A pass-by-reference language would pass not the reference itself, but a reference to the reference.

编辑-这里有一篇关于这个主题的博客文章。(注意那篇文章的注释,解释了c++并没有真正的引用传递。这是真的。然而,c++所拥有的是创建对普通变量的引用的能力,可以在函数调用时显式地创建指针,也可以在调用其参数类型签名要求这样做的函数时隐式地创建指针。这些都是JavaScript不支持的关键。)


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

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

inc('a');

alert(a); // 2

是的,实际上你可以在不访问全局变量的情况下完成:

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

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

    return init;
})();

inc();

简单的对象

函数foo(x) { //使用其他上下文函数 //修改' x '属性,增加值 x.value + +; } //初始化' ref '为对象 Var = { // ' value '在' ref '变量对象中 //初始值为' 1 ' 值:1 }; //用对象值调用函数 foo (ref); //再次调用带有对象值的函数 foo (ref); console.log (ref.value);//打印"3"


自定义对象

对象rvar

/** * Aux function to create by-references variables */ function rvar(name, value, context) { // If `this` is a `rvar` instance if (this instanceof rvar) { // Inside `rvar` context... // Internal object value this.value = value; // Object `name` property Object.defineProperty(this, 'name', { value: name }); // Object `hasValue` property Object.defineProperty(this, 'hasValue', { get: function () { // If the internal object value is not `undefined` return this.value !== undefined; } }); // Copy value constructor for type-check if ((value !== undefined) && (value !== null)) { this.constructor = value.constructor; } // To String method this.toString = function () { // Convert the internal value to string return this.value + ''; }; } else { // Outside `rvar` context... // Initialice `rvar` object if (!rvar.refs) { rvar.refs = {}; } // Initialize context if it is not defined if (!context) { context = this; } // Store variable rvar.refs[name] = new rvar(name, value, context); // Define variable at context Object.defineProperty(context, name, { // Getter get: function () { return rvar.refs[name]; }, // Setter set: function (v) { rvar.refs[name].value = v; }, // Can be overrided? configurable: true }); // Return object reference return context[name]; } } // Variable Declaration // Declare `test_ref` variable rvar('test_ref_1'); // Assign value `5` test_ref_1 = 5; // Or test_ref_1.value = 5; // Or declare and initialize with `5`: rvar('test_ref_2', 5); // ------------------------------ // Test Code // Test Function function Fn1(v) { v.value = 100; } // Test function test(fn) { console.log(fn.toString()); console.info(fn()); } // Declare rvar('test_ref_number'); // First assign test_ref_number = 5; test(() => test_ref_number.value === 5); // Call function with reference Fn1(test_ref_number); test(() => test_ref_number.value === 100); // Increase value test_ref_number++; test(() => test_ref_number.value === 101); // Update value test_ref_number = test_ref_number - 10; test(() => test_ref_number.value === 91);


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.

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

像字符串和数字这样的基本类型变量总是按值传递。 数组和对象通过引用或基于以下条件的值传递:

如果你正在设置一个对象或数组的值,它是通过值传递。 Object1 = {prop: "car"}; Array1 = [1,2,3]; 如果你正在改变一个对象或数组的属性值,那么它是引用传递。 中的object1。道具= "汽车"; Array1 [0] = 9;

Code

函数passVar(obj1, obj2, num) { 其中obj1。道具= "笔记本电脑";//将改变原来的 Obj2 ={道具:"电脑"};//不影响原 Num = Num + 1;//不影响原 } Var object1 = { 道具:“车” }; Var object2 = { 道具:“自行车” }; Var number1 = 10; passVar(object1, object2, number1); console.log(中的object1);//输出:对象{道具:"笔记本电脑"} console.log (object2);//输出:Object {prop: "bike"} console.log (number1);//输出:10


其实很简单。问题在于,一旦传递了经典参数,您就会被限定在另一个只读区域。

解决方案是使用JavaScript的面向对象设计来传递参数。这与将参数放在全局/作用域变量中是一样的,但更好…

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

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

你也可以承诺一些东西来享受著名的连锁店: 这就是全部,像承诺一样的结构

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

或者更好的是……

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

另一种通过引用传递任何(局部的,基本的)变量的方法是通过eval“动态”地用闭包包装变量。这也适用于“use strict”。(注意:注意eval对JavaScript优化器不友好,并且变量名周围缺少引号可能会导致不可预测的结果)

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

现场示例:https://jsfiddle.net/t3k4403w/


其实有一个很好的解决方案:

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"]

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

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

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

例子:

假设通过在参数列表中使用'ref'这样的特殊关键字来支持传递参数。我的代码可能是这样的:

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

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

相反,我更喜欢这样做:

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

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

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

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

相反,我实际上更喜欢在对象中返回两个新值,就像这样:

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

这些代码示例非常简化,但它大致演示了我个人如何处理这些东西。它帮助我把各种责任放在正确的位置。

快乐的编码。:)


我完全明白你的意思。同样的事情在Swift中是没有问题的。底线是使用let,而不是var。

原语是按值传递的,但在迭代时var i的值没有复制到匿名函数中,这一点至少令人惊讶。

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

JavaScript可以在函数中修改数组项(它作为对象/数组的引用传递)。

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

下面是另一个例子:

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]

撇开“参考资料传递”的讨论不谈,那些仍然在寻找上述问题的解决方案的人可以使用:

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

我喜欢在JavaScript中解决引用的不足,就像这个例子所显示的那样。

这样做的本质是,您不必尝试创建一个通过引用。相反,您可以使用返回功能,并使其能够返回多个值。因此,不需要在数组或对象中插入值。

var x = "First"; var y = "Second"; var z = "Third"; log('Before call:',x,y,z); with (myFunc(x, y, z)) {x = a; y = b; z = c;} // <-- Way to call it log('After call :',x,y,z); function myFunc(a, b, c) { a = "Changed first parameter"; b = "Changed second parameter"; c = "Changed third parameter"; return {a:a, b:b, c:c}; // <-- Return multiple values } function log(txt,p1,p2,p3) { document.getElementById('msg').innerHTML += txt + '<br>' + p1 + '<br>' + p2 + '<br>' + p3 + '<br><br>' } <div id='msg'></div>


如果你想通过引用传递变量,一个更好的方法是通过在对象中传递参数,然后使用window开始更改值:

window["varName"] = value;

例子:

// Variables with first values
var x = 1, b = 0, f = 15;


function asByReference (
    argumentHasVars = {},   // Passing variables in object
    newValues = [])         // Pass new values in array
{
    let VarsNames = [];

    // Getting variables names one by one
    for(let name in argumentHasVars)
        VarsNames.push(name);

    // Accessing variables by using window one by one
    for(let i = 0; i < VarsNames.length; i += 1)
        window[VarsNames[i]] = newValues[i]; // Set new value
}

console.log(x, b, f); // Output with first values

asByReference({x, b, f}, [5, 5, 5]); // Passing as by reference

console.log(x, b, f); // Output after changing values

使用解构这里是一个例子,我有3个变量,对每个我做多个操作:

如果value小于0,则改为0, 如果大于255,则改为1, 否则,将数字俯冲255以将0-255的范围转换为0-1的范围。

let a = 52.4, b = -25.1, c = 534.5;
[a, b, c] = [a, b, c].map(n => n < 0 ? 0 : n > 255 ? 1 : n / 255);
console.log(a, b, c); // 0.20549019607843136 0 1

由于我们没有javascript的引用传递功能,唯一的方法是让函数返回值,并让调用者分配它:

So

"makePretty(myArray[x]);"

应该是

"myArray[x] = makePretty(myArray[x]);"

这是在函数内部需要赋值的情况下,如果只需要突变,那么传递对象并突变它就足够了