4

当将原语作为参数传递给 JavaScript 函数时,是传递给函数的值的副本(即正在创建的新变量),还是只是指向内存中变量位置的指针,就像对象发生的情况一样?然而,由于对象是可变的,因此很容易证明,因为原语是不可变的,所以它们总是会被重新分配,因此很难判断幕后发生了什么。

在以下代码(http://jsbin.com/egufog/2/edit)中演示了我的意思:

var pvalue = 'foo'; //primitive

var ovalue = { foo : 'foo' }; //object

changeMe( pvalue, ovalue ); //changes values

console.log( pvalue, ovalue ); //pvalue unchanged, ovalue was changed

reassignMe( ovalue ); //reassigns the object, breaking the reference

console.log( ovalue ); //ovalue remains unchanged

function changeMe( primitive, obj ){
  primitive = 'bar'; //did this reassign the pointer or just create another variable?

  obj.foo = 'bar'; //updates the object in memory
}

function reassignMe( obj ) {
  obj = { baz : 'baz' }; //reassignment breaks the pointer reference
}
4

3 回答 3

3

当将原语作为参数传递给 JavaScript 函数时,是传递给函数的值的副本(即正在创建的新变量),还是只是指向内存中变量位置的指针,就像对象发生的情况一样?

函数参数总是创建一个新变量,即一个名称包含一个值的槽。由于 javascript 没有指针,它保存的位置而不是变量的位置。

由于原语是不可变的,它们总是会被重新分配,因此很难判断幕后发生了什么。

确切地说,我们不知道。但是由于它们是不可变的,因此是否为变量分配了值本身的副本或值的位置都没有区别。JS 引擎可以自由选择——我希望对大字符串使用引用,但不是数字或布尔值。

changeMe( 'foo' )
function changeMe( primitive, obj ){
    primitive = 'bar'; //did this reassign the pointer or just create another variable?
}

primitive自从您调用该函数以来,就没有新变量存在。它之前保存了值'foo'(或指向它的指针),现在确实保存了值'bar'(或指向它的指针)。

只有对于对象,我们才知道保存它们的变量包含指向内存中数据结构的指针——它们被称为“引用值”(与原始值相反)。如果您改变数据,您可以从引用该对象的每个变量中看到。

于 2013-06-26T09:18:54.677 回答
1

我觉得说得太简单了

console.log( pvalue, ovalue ); //pvalue unchanged, ovalue was changed

如果我们将 pvalue 和 ovalue 视为对对象的引用,我们将引用保存在堆栈中,为被调用函数制作副本以供使用,然后调用该函数。此时,被调用函数有它自己的引用,但它仍然指向相同的对象,因此能够改变它们

如果我们重新分配传递给函数的引用,例如

primitive = 'bar'; //did this reassign the pointer or just create another variable?
或者
obj = { baz : 'baz' }; //reassignment breaks the pointer reference

然后我们所做的就是更改原始引用的副本,其范围仅限于被调用的函数。回到调用函数,我们从堆栈中取出原始引用

于 2013-06-25T21:22:07.057 回答
0

据我所知,当原始类型在函数的参数中传递时,它们按值传递,原始值的副本在函数中传递。这意味着如果在函数中更改参数的值,则变量的“原始”值是完整的。

var pvalue = 'foo'; //primitive

function changeMe(prim) {
    prim = 'bar';
}
changeMe(pvalue);
console.log(pvalue); // pvalue remains foo (unchanged)

但是,如果您尝试对对象进行相同操作,它将更改“原始”对象,因为它在函数中的新变量也将指向原始对象。但这并不意味着它是通过引用传入的。看一下这个。

function changeMe(obj) {
    obj.foo = "foo";
    obj = new Object();
    obj.foo = "bar";
}

var ovalue = { foo : null };
changeMe(ovalue);

alert(ovalue.foo); // Changed to foo but not to bar

这意味着如果 obj 是通过引用传入的,那么当我将新对象分配给 obj 然后更改属性时,它也会将原始对象的 foo 属性更改为 bar。

所以我的想法是,对象也是按值传递的,例如,当您使用该值来分配属性时,它将指向与以前相同的对象。但是,如果您在函数中将 obj 重新分配给一个新对象,那么这个新对象将指向一个不同的本地对象,该对象可以在创建它的函数范围内访问。

于 2013-06-25T21:12:47.557 回答