原语如何在JavaScript中作为参数传递给函数?

时间:2013-06-25 20:34:28

标签: javascript

当将一个原语作为参数传递给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
}

3 个答案:

答案 0 :(得分: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'(或指向它的指针)。

只有对象我们知道持有它们的变量包含指向内存中数据结构的指针 - 它们被称为“参考值”(与原语相反)那些)。如果改变数据,可以从引用该对象的每个变量中看到它。

答案 1 :(得分: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

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

答案 2 :(得分: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是通过refence传入的,那么当我将新的Object分配给obj然后更改了属性时它也会将原始对象的foo属性更改为bar。

所以我想到的是,对象也是通过值传递的,当你使用该值来分配属性时,它会将它指向与之前相同的对象。但是,如果在函数中将obj重新分配给新的Object,则此新对象将指向可以在其创建的函数范围内访问的不同本地Object。