如何在JavaScript中将基元作为参数传递到函数中

How are primitives passed into functions as arguments in JavaScript?

本文关键字:参数传递 函数 JavaScript      更新时间:2023-09-26

将基元作为参数传递到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
}

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

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

由于基元是不可变的,它们总是会被重新分配,所以很难判断幕后发生了什么。

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

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

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

只有对于对象,我们知道保存它们的变量包含指向内存中数据结构的指针-它们被称为"引用值"(与基元相反)。如果你改变数据,你可以从引用对象的每个变量中看到这一点。

我认为说太简单了

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

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

据我所知,当基元类型在函数的参数中传递时,它们会按值传递,并且基元值的副本会在函数中传递。这意味着,如果在函数中更改参数的值,那么变量的"原始"值是完整的。

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重新分配给一个新对象,那么这个新对象将指向一个不同的本地对象,该对象可以在其创建的函数范围内访问。