javascript是否通过引用传递?

Does Javascript pass by reference?

javascript是传递引用还是传递值?下面是一个来自javascript的例子:好的部分。我对矩形函数的my参数非常困惑。它实际上是undefined,并在函数内部重新定义。没有原始参考。如果我从函数参数中删除它,内部区域函数将无法访问它。

这是一个终结吗?但没有返回函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var shape = function (config) {
    var that = {};
    that.name = config.name ||"";
    that.area = function () {
        return 0;
    };
    return that;
};
var rectangle = function (config, my) {
    my = my || {};
    my.l = config.length || 1;
    my.w = config.width || 1;
    var that = shape(config);
    that.area = function () {
        return my.l * my.w;
    };
    return that;
};
myShape = shape({
    name:"Unhnown"
});
myRec = rectangle({
    name:"Rectangle",
    length: 4,
    width: 6
});
console.log(myShape.name +" area is" + myShape.area() +"" + myRec.name +" area is" + myRec.area());


原语按值传递,对象按"引用副本"传递。

具体来说,当您传递一个对象(或数组)时,您正在(不可见地)传递对该对象的引用,并且可以修改该对象的内容,但是如果您试图覆盖引用,它将不会影响调用方持有的引用的副本,即引用本身是通过值传递的:

1
2
3
4
5
6
7
8
9
10
11
function replace(ref) {
    ref = {};           // this code does _not_ affect the object passed
}

function update(ref) {
    ref.key = 'newvalue';  // this code _does_ affect the _contents_ of the object
}

var a = { key: 'value' };
replace(a);  // a still has its original value - it's unmodfied
update(a);   // the _contents_ of 'a' are changed


这样想:

每当你用ecmascript创建一个对象,这个对象就形成在一个神秘的ecmascript通用的地方,在那里没有人能够得到。你所得到的只是在这个神秘的地方对那个物体的引用。

1
var obj = { };

即使是obj也只是一个对象的引用(它位于那个特别美妙的地方),因此,您只能传递这个引用。实际上,任何一段访问obj的代码都会修改远方的对象。


我的2美分…JavaScript是否通过引用或值传递参数与此无关。真正重要的是分配与变异。

我在这里写了一个更长、更详细的解释(javascript是传递引用还是传递值语言?)

当您传递任何东西(无论是对象还是原语)时,所有的javascript都会在函数内部分配一个新的变量…就像使用等号(=)

该参数在函数内部的行为方式与使用等号分配新变量时的行为完全相同。举几个简单的例子。

1
2
3
4
5
6
7
8
9
10
11
var myString = 'Test string 1';

// Assignment - A link to the same place as myString
var sameString = myString;

// If I change sameString, it will not modify myString,
// it just re-assigns it to a whole new string
sameString = 'New string';

console.log(myString); // logs 'Test string 1';
console.log(sameString); // logs 'New string';

如果我将mystring作为参数传递给一个函数,它的行为就好像我只是将它赋给了一个新的变量。现在,让我们做同样的事情,但是使用函数而不是简单的赋值

1
2
3
4
5
6
7
8
9
10
11
12
function myFunc(sameString) {

    // Re assignment.. again, it will not modify myString
    sameString = 'New string';
}

var myString = 'Test string 1';

// This behaves the same as if we said sameString = myString
myFunc(myString);

console.log(myString); // Again, logs 'Test string 1';

将对象传递给函数时,您可以修改对象的唯一原因是您没有重新分配…相反,对象可以更改或改变….同样,它的工作方式也是一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var myObject = { name: 'Joe'; }

// Assignment - We simply link to the same object
var sameObject = myObject;

// This time, we can mutate it. So a change to myObject affects sameObject and visa versa
myObject.name = 'Jack';
console.log(sameObject.name); // Logs 'Jack'

sameObject.name = 'Jill';
console.log(myObject.name); // Logs 'Jill'

// If we re-assign it, the link is lost
sameObject = { name: 'Howard' };
console.log(myObject.name); // Logs 'Jill'

如果要将myObject作为参数传递给函数,它的行为就好像我只是将它赋给了一个新的变量。同样,同样的事情,同样的行为,但是有一个函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function myFunc(sameObject) {

    // We mutate the object, so the myObject gets the change too... just like before.
    sameObject.name = 'Jill';

    // But, if we re-assign it, the link is lost
    sameObject = { name: 'Howard' };
}

var myObject = { name: 'Joe'; }

// This behaves the same as if we said sameObject = myObject;
myFunc(myObject);
console.log(myObject.name); // Logs 'Jill'

每次将变量传递给函数时,都会对参数的名称进行"赋值",就像使用等号(=)一样。

始终记住等号(=)表示赋值。向函数传递参数也意味着赋值。它们是相同的,两个变量以完全相同的方式连接。

修改一个变量影响另一个变量的唯一时间是在基础对象发生变化时。

区分对象和原语没有意义,因为它的工作方式与没有函数的工作方式完全相同,只是使用等号来分配给一个新变量。


和C一样,最终,一切都是通过价值传递的。与C不同,实际上您不能备份和传递变量的位置,因为它没有指针只是引用。

它所拥有的引用都是对象,而不是变量。有几种方法可以达到相同的结果,但它们必须手工完成,而不仅仅是在调用或声明站点添加关键字。


函数参数要么通过值传递,要么通过共享传递,但绝不会通过JavaScript中的引用传递!

按值调用

基元类型按值传递:

1
2
3
4
5
6
7
8
9
10
var num = 123, str ="foo";

function f(num, str) {
  num += 1;
  str +="bar";
  console.log("inside of f:", num, str);
}

f(num, str);
console.log("outside of f:", num, str);

函数范围内的重新分配在周围范围内不可见。

这也适用于Strings,它是复合数据类型,但不可变:

1
2
3
4
5
6
7
8
9
var str ="foo";

function f(str) {
  str[0] ="b"; // doesn't work, because strings are immutable
  console.log("inside of f:", str);
}

f(str);
console.log("outside of f:", str);

共享调用

对象,也就是说,所有不是基元的类型都是通过共享传递的。保存对象引用的变量实际上只保存该引用的一个副本。如果javascript采用按引用调用的评估策略,则变量将保留原始引用。这是共享和引用之间的关键区别。

这种区别的实际后果是什么?

1
2
3
4
5
6
7
8
9
var o = {x:"foo
<hr><P>javascript是传递值。对于基元,传递基元的值。对于对象,传递对象的引用"
value"。</P><P>对象示例:</P>[cc lang="javascript"]var f1 = function(inputObject){
    inputObject.a=2;
}
var f2 = function(){
    var inputObject={"
a":1};
    f1(inputObject);
    console.log(inputObject.a);
}

当传递引用并更新引用中的"a"值时,调用f2会将"a"值打印为2而不是1。

带基本体的示例:

1
2
3
4
5
6
7
8
var f1 = function(a){
    a=2;
}
var f2 = function(){
    var a =1;
    f1(a);
    console.log(a);
}

调用F2会将"A"值打印为1。


In the interest of creating a simple example that uses const...

1
2
3
4
5
6
7
8
9
10
11
const myRef = { foo: 'bar' };
const myVal = true;

function passes(r, v) {
  r.foo = 'baz';
  v = false;
}

passes(myRef, myVal);

console.log(myRef, myVal); // Object {foo:"baz"} true

实际上,alnitak是正确的,并且易于理解,但最终在javascript中,所有东西都是按值传递的。

对象的"值"是什么?它是对象引用。

当你传入一个对象时,你会得到这个值的一个副本(因此Alnitak描述的"引用的副本")。如果更改此值,则不会更改原始对象,而是更改引用的副本。


"全局"javascript变量是window对象的成员。您可以作为窗口对象的成员访问引用。

1
2
3
4
5
6
7
var v ="initialized";
function byref(ref) {
 window[ref] ="changed by ref";
}
byref((function(){for(r in window){if(window[r]===v){return(r);}}})());
// could also be called like... byref('v');
console.log(v); // outputs changed by ref

注意,上面的示例不适用于函数中声明的变量。


没有purism,我认为在javascript中通过引用来模拟标量参数的最佳方法是使用对象,就像前面的答案所说的那样。

但是,我做了一些不同的事情:

我已经在函数调用中进行了对象分配,因此可以看到函数调用附近的引用参数。它提高了源代码的可读性

在函数声明中,我将属性作为注释放在一起,原因非常相同:可读性。

1
2
3
4
5
6
7
8
9
10
var r;

funcWithRefScalars(r = {amount:200, message:null} );
console.log(r.amount +" -" + r.message);


function funcWithRefScalars(o) {  // o(amount, message)
  o.amount  *= 1.2;
  o.message ="20% increase";
}

在上面的例子中,null清楚地表示一个输出参考参数。

出口:

1
240 - 20% Increase

在客户端,console.log应替换为alert

V.V.V.

另一种更具可读性的方法:

1
2
3
4
5
6
7
8
9
var amount, message;

funcWithRefScalars(amount = [200], message = [null] );
console.log(amount[0] +" -" + message[0]);

function funcWithRefScalars(amount, message) {  // o(amount, message)
   amount[0]  *= 1.2;
   message[0] ="20% increase";
}

在这里,您甚至不需要创建新的虚拟名称,如上面的r


我看不到人们试图证明这一点的例子。我只看到传递值。

对于保存对象引用的变量,引用是这些变量的值,因此将传递引用,然后传递值。

在这样的声明中:

1
2
3
4
var a = {
  b:"foo",
  c:"bar"
};

"a"的值不是对象,而是(到目前为止)对它的引用。换句话说,对象不在变量A中,对它的引用是。我认为对于只熟悉JavaScript的程序员来说,这似乎很困难。但是对于那些知道Java,C,C和C的人也很容易。


基元按值传递。但是,如果只需要读取primitve的值(在调用函数时不知道值),则可以传递函数,该函数在需要时检索值。

1
2
3
4
5
6
7
8
function test(value) {
  console.log('retrieve value');
  console.log(value());
}

// call the function like this
var value = 1;
test(() => value);