一文详解JavaScript中的按值传递和按引用传递

 更新时间:2024年05月07日 11:01:51   作者:刘同学有点忙  
编程语言中,把一个变量的值赋值给另一个变量,或者给函数调用传递参数有两种方式:按值传递和按引用传递,本文将给大家详细介绍JavaScript中的按值传递和按引用传递,需要的朋友可以参考下

JavaScript中几乎都是按值传递

编程语言中,把一个变量的值赋值给另一个变量,或者给函数调用传递参数有两种方式:按值传递按引用传递

JavaScript中几乎都是按值传递。我们看一个例子:

let a = 1
let b = a
b = 2
console.log(a) // 1
  • 上面的代码,声明了一个变量a,赋值为1;
  • 然后又声明了一个变量b,将变量a的值1赋值给变量b,此时变量b的值也是1;
  • 接着我们将变量b的值修改为2;
  • 此时打印变量a的值应该仍然是1,而不是2。

这就是按值传递,我们把变量a的值赋值给变量b的时候,只是把1这个值复制了一份给变量b,变量b的值的修改并不会影响到变量a的值。

很好,到目前为止,我们说上面的代码是按值传递很好理解,很符合我们的直觉。

上面是基元值的情况,如果换成引用类型的值呢?看下面的代码。

const foo = {
    a: 1
}
const bar = foo
bar.a = 2
console.log(foo.a) // 2
  • 上面的代码声明了一个变量foo,给它赋值了一个对象;
  • 然后又声明了一个变量bar,把变量foo指向的对象赋值给变量bar
  • 接着我们通过bar.a把对象的属性a修改为2;
  • 我们发现foo.a也被修改了!

说好的按值传递呢?如果是按值传递,修改bar.a不应该导致foo.a被修改啊,这好像不太符合直觉啊?难道引用类型的值是按引用传递吗?

并不是。JavaScript中引用类型的值也是按值传递的,只不过这个传递的值是对象在堆内存中的地址。

看上面的图片可以更清楚地理解这个过程,假设对象在堆内存中的地址是0x100,那么按值传递的就是0x100这个地址。bar.a修改了对象里属性的值,但是foobar仍都然都指向地址0x100,所以通过bar.a修改对象属性值会反应到foo.a上。

上面的图只是一个粗略的方便理解的图,下面的图可能更符合代码实际的内存分布。

另外,仍然是上面的代码,如果我们稍加改动,给变量bar赋值一个新的对象,那么变量foo和变量bar就指向不同的内存地址了,修改变量bar将不再导致变量foo被修改。有些支持按引用传递的语言,类似的操作会导致变量foo也被修改,这个我不太了解,所以就不展开了。

const foo = {
    a: 1
}
let bar = foo
bar = {
    a: 2
}
console.log(foo.a) // 1

ES Module中的live bindings

前面我们说了,JavaScript中几乎都是按值传递,这样说通常都有例外。ES Module中export导出的变量被称为live bindings(实时绑定),这是JavaScript中唯一按引用传递的情况。

// a.js
export let count = 1
export function increment() {
    count++
}
// b.js
import { count, increment } from './a.js'
console.log(count) // 1
// count = 2 // import的变量是只读的,不能修改,尝试修改会报错 TypeError: Assignment to constant variable.
increment()
console.log(count) // ?

让我们暂停下来,思考一下,上面的代码中,第二个console.log(count)会输出什么?

答案是2。ES Module中export的变量,其它模块import进来之后是只读的,尝试修改会报错。但是export变量的模块可以另外导出一个方法用来修改这个变量,变量的修改会同步反应在两个模块中,这种情况被称为live bindings,是按引用传递的。

上面类似的代码在CommonJs中的执行结果截然不同。

// a.js
let count = 1
function increment() {
    count++
}
module.exports = {
    count,
    increment
}
const { count, increment } = require('./a.js')
console.log(count) // 1
count = 2  // 可以修改
console.log(2) // 2
increment()
console.log(count) // 是2而不是3

require导入的变量是可以被修改的,上面的代码中最后的console.log(count)的值是2而不是3,因为这里count是按值传递的。

总结

  • JavaScript中几乎都是按值传递。
  • ES Module中export导出的变量是JavaScript中唯一的按引用传递,这被称作live bindings。另外export导出的变量是只读的,在模块外部不允许修改它的值,通常可以额外导出一个方法用来修改这个变量。

以上就是一文详解JavaScript中的按值传递和按引用传递的详细内容,更多关于JavaScript按值和按引用传递的资料请关注脚本之家其它相关文章!

相关文章

  • JavaScript实现的开关灯泡点击切换特效示例

    JavaScript实现的开关灯泡点击切换特效示例

    这篇文章主要介绍了JavaScript实现的开关灯泡点击切换特效,涉及javascript事件响应及页面元素属性动态操作相关实现技巧,需要的朋友可以参考下
    2019-07-07
  • 20行JS代码实现网页刮刮乐效果

    20行JS代码实现网页刮刮乐效果

    下面小编就为大家带来一篇20行JS代码实现网页刮刮乐效果。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • JS addEventListener()和attachEvent()方法实现注册事件

    JS addEventListener()和attachEvent()方法实现注册事件

    这篇文章主要介绍了JS addEventListener()和attachEvent()方法实现注册事件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • JavaScript控制网页层收起和展开效果的方法

    JavaScript控制网页层收起和展开效果的方法

    这篇文章主要介绍了JavaScript控制网页层收起和展开效果的方法,涉及javascript操作网页元素动态效果的技巧,非常具有实用价值,需要的朋友可以参考下
    2015-04-04
  • JavaScript 创建随机数和随机图片

    JavaScript 创建随机数和随机图片

    关于javascript随机数的,很早以前的文章了,不过内容还是不错的,如果想要更多的效果,可以去脚本之家搜下。
    2009-12-12
  • Javascript将字符串日期格式化为yyyy-mm-dd的方法

    Javascript将字符串日期格式化为yyyy-mm-dd的方法

    日期格式化相信对于大家来说再熟悉不过,最近工作中自己利用Javascript就写了一个,现在将实现的代码分享给大家,希望对有需要的朋友们能有所帮助,感兴趣的朋友们下面来一起看看吧。
    2016-10-10
  • javascript中indexOf技术详解

    javascript中indexOf技术详解

    indexOf()函数用于查找子字符串在当前字符串中第一次出现的位置。该函数属于String对象,所有主流浏览器均支持该函数。下面我们就来详细探讨下javascript的index0f()函数
    2015-05-05
  • 微信小程序wx:for和wx:for-item的用法详解

    微信小程序wx:for和wx:for-item的用法详解

    这篇文章主要介绍了微信小程序wx:for和wx:for-item的正确用法,wx:for是循环数组,wx:for-item即给列表赋别名,文中给大家列出来几个错误用法,大家一起学习下
    2018-04-04
  • JS小技巧之通过字符串追加元素

    JS小技巧之通过字符串追加元素

    这篇文章主要介绍了JS小技巧之通过字符串追加元素方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • 原生JS实现网络彩票投注效果

    原生JS实现网络彩票投注效果

    分享一个最近模仿市面彩票系统写个小案例,没有使用任何后台,从投注到开奖再到返奖都是用原生JS实现的。
    2016-09-09

最新评论