惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
博客园_首页
IT之家
IT之家
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Vercel News
Vercel News
美团技术团队
D
Docker
WordPress大学
WordPress大学
T
Tailwind CSS Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
The Cloudflare Blog
Y
Y Combinator Blog
F
Fortinet All Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
G
Google Developers Blog
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
月光博客
月光博客
MongoDB | Blog
MongoDB | Blog
S
SegmentFault 最新的问题
GbyAI
GbyAI
Hugging Face - Blog
Hugging Face - Blog
Microsoft Azure Blog
Microsoft Azure Blog
A
About on SuperTechFans

小蘿蔔丁

About 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。
小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术...
2018-01-13 · via 小蘿蔔丁

最近在研究 lambda 演算 中的 η-变换 在 JavaScript 中的应用,偶然在 stackoverflow 上看到一个比较有意思的问题。关于 JavaScript 的求值策略,问 JS 中函数的参数传递是按值传递还是按引用传递?回答很经典。

一栗以蔽之

function changeStuff(a, b, c) {  a = a * 10  b.item = 'changed'  c = { item: 'changed' }}var num = 10var obj1 = { item: 'unchanged' }var obj2 = { item: 'unchanged' }changeStuff(num, obj1, obj2)console.log(num) // 10console.log(obj1.item) // changedconsole.log(obj2.item) // unchanged
  • 如果说 JS 中函数的参数传递是按值传递,那么在函数changeStuff内部改变b.item的值将不会影响外部的obj1对象的值。
  • 如果说 JS 中函数的参数传递是按引入传递,那函数changeStuff内部所做的改变将会影响到函数外部所有的变量定义,num将会变成 100、obj2.item将会变成changed。很显然实际不是这样子的。

所以不能说 JS 中函数的参数传递严格按值传递按引入传递。总的来说函数的参数都是按值传递的。JS 中还采用一种参数传递策略,叫按共享传递。这要取决于参数的类型。

  • 如果参数是基本类型,那么是按值传递的;
  • 如果参数是引用类型,那么是按共享传递的。

参数传递

ECMAScript 中所有函数的参数都是按值传递的。也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。基本类型值的传递如同基本类型变量的复制一样,而引用类型值的传递,则如同引用类型变量的复制一样。-- 《JavaScript 高级程序设计》

红宝书上讲所有函数的参数都是按值传递的,到底是不是呢?让我们分析下上面的栗子:

按值传递

JavaScript 中基本类型作为参数的策略为 按值传递(call by value):

function foo(a) {  a = a * 10}var num = 10foo(num)console.log(num) // 10 没有变化

这里看到函数内部参数的改变并没有影响到外部变量。按值传递没错。

按共享传递

JavaScript 中对象作为参数传递的策略为 按共享传递(call by sharing):

  • 修改参数的属性将会影响到外部对象
  • 重新赋值将不会影响到外部对象

按上面栗子函数内部修改了参数b的属性item,会影响到函数外部对象,因而obj1的属性item也变了。

function bar(b) {  b.item = 'changed'  console.log(b === obj1) // true}var obj1 = { item: 'unchanged' }bar(obj1)console.log(obj1.item) // changed 修改参数的属性将会影响到外部对象

b === obj1打印结果为true可以看出,函数内部修改了参数的属性并没有影响到参数的引用。bobj1共享一个对象地址,所以修改参数的属性将会影响到外部对象。

而将参数c重新赋值一个新对象,将不会影响到外部对象。

function baz(c) {  c = { item: 'changed' }  console.log(c === obj2) // false}var obj2 = { item: 'unchanged' }baz(obj2)console.log(obj2.item) // unchanged 重新赋值将不会影响到外部对象

将参数c重新赋值一个新对象,那么c就绑定到了一个新的对象地址,c === obj2打印结果为false,判断他们不再共享同一个对象地址。它们各自有独立的对象地址。所以重新赋值将不会影响到外部对象。

总结

可以说 按共享传递按值传递 的特例,传递的是引用地址的拷贝。所以红宝书上说的也没错。

可以把 ECMAScript 函数的参数想象成局部变量。-- 《JavaScript 高级程序设计》

延伸 - 惰性求值

前面了解到了所有函数的参数都是按值传递的。JavaScript 中参数是必须先求值再作为实参传入函数的。但是在 ES6 中有一个特例。

参数默认值不是传值的,而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的。 -- 《ECMAScript 6 入门》

let x = 99function foo(p = x + 1) {  console.log(p)}foo() // 100x = 100foo() // 101

上面代码中,参数p的默认值是x + 1。这时,每次调用函数foo,都会重新计算x + 1,而不是默认p等于 100。

参考

求值策略

Is JavaScript a pass-by-reference or pass-by-value language?

ES6 中函数参数的默认值