关于JavaScript中的值传递和引用传递的解释

两大类基本类型

  1. 原始类型

    Null
    Undefined
    Boolean
    Number
    String
    Symbol
    BigInt(ES10 Chrome已支持)

  2. 对象类型
    Object

首先明确一点,ECMAScript中所有的函数的参数都是按值传递的。

三个例子带你搞懂为什么都是按值传递的

let foo = 'foo';
function update(foo) {
	foo = 'bar';
}
update(foo);
console.log(foo); // 'foo'

运行一下就知道上面这个例子最终打印的是'foo',为什么?因为函数参数仅仅是被传入变量复制给了的一个局部变量,在函数内部改变这个变量不会对外部产生影响。

再看下面这个:

let foo = { name: 'bar' };
function update(foo) {
	foo.name = 'opt';
}
update(foo);
console.log(foo.name); // 'opt'

这个结果会让你疑惑,是不是参数是引用类型的就是引用传递?
其实并不是,当函数参数是引用类型的时候,我们同样的将参数复制了一个副本到局部变量,但是这个复制的副本其实是一个指向堆内存中的地址,也就是说我们在函数内部通过引用对被引用的对象的属性进行了重新赋值的操作,实际上和在外部变量指向堆内存中的值相同,但这并不是引用传递。

最后一个例子:

let foo = {};
function update(foo) {
	foo.name = 'bar';
	foo = { name: 'opt' };
}
update(foo);
console.log(foo.name); // 'bar'

不要晕,根据第二个例子我们知道传进到这个函数中的'foo'其实是一个指向外面声明的那个空对象的一个新的引用,函数内第一步'foo.name = 'bar';这一步其实是在外面声明空对象中创建了一个'name'属性并赋值'bar'。但是第二步'foo = { name: 'opt' }' 其实是改变了这个引用指向的对象,也就是说这个函数内部第一行原来指向外部声明的那个{}的引用在第二行指向了新对象,因而这个新的引用没有改变外面foo引用指向的对象,所以最终打印出了'bar'

其实update(foo)最终隐式地返回了这个指向新对象的引用,可以自己打印一下看看。
总结:函数参数传递的并不是变量的引用,而是变量拷贝的副本,当变量是原始类型时,这个副本就是值本身,当变量是引用类型时,这个副本是指向堆内存的地址。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值