写了这样一段代码,执行结果和预期不一样,为什么?

Tenadolanter
  • 98

代码如下:

const testFunc = (str)=>{
    str = 'my test str'
}
let str = ''
testFunc(str)
console.log(str)

2020年01月15日23:18:16晚上新加:

一时迷糊了,因为经常直接在函数中操作对象,当换成字符串,发现不起作用后没有反应过来。如下代码:

let a = { name: '11111', sex: 'nan' }
const setName = (param) => {
    console.log(param === a)
    param.name = 'test'
}
setName(a);
console.log(a)

如果把上面的setName(a)换成setName(a.name)、把param.name = 'test'换成param = 'test',可以看到结果又不一样了。

出现上面结果的原因是没有完全理解全局作用域、函数作用域

  • 当传入参数是常量的时候,对参数的更改是在函数作用域里面,并不会影响全局作用域的值。
  • 当传入的参数是对象的时候,虽然函数外部是全局作用域,参数是函数作用域,但是由于对象使用的是同一块内存,当内容改变后,全局作用域里面的值和函数作用域里面的值都发生改变。
评论
阅读 1k
5 个回答

ECMAScript中所有的函数中的参数是按值传递的,函数参数传递的并不是变量的引用,而是变量的拷贝副本。
当函数参数是对象时(即引用类型,并不是单纯的一个值,而是指向该对象的堆内存中的地址而已),所以此时函数内部对对象的属性进行操作,实际上和外部变量指向堆内存中的值是相同。举个例子
let A = { a : 1, b : 2 };
let B = A
B.a = 3
那么 A.a 也等于 3
有兴趣的话楼主你可以搜索 栈内存与堆内存

需要澄清的一点是变量储存引用类型和基本类型的时候,「变量值」是什么

考虑这段代码:

const anyIns = { a: 1 }
const fn = any => { // 新建变量 any,存储了引用类型的指针
  console.log(any === anyIns) // 两个指针一样,所以是 true
  any.a = 2 // 指针对应的内存修改
}
console.log(anyIns)
fn(anyIns)
console.log(anyIns)

所以结果是

{ a: 1 }
true
{ a: 2 }

对于基本类型:

const anyIns = 1
const fn = any => { // 新建变量 any,存储了基本类型的值
  console.log(any === anyIns) // 值相等
  any = 2 // 变量的值进行了修改
}
console.log(anyIns)
fn(anyIns)
console.log(anyIns)

所以结果是

1
true
1

js的坑之一,复杂类型,基本类型。址与值

不是全局作用域、函数作用域的问题,而是引用数据类型和基础数据类型的问题。

引用数据类型传入函数时,传入的是引用,而非值本身。

引用可以简单理解为指向内存空间的地址,也是字符串,如下图。

image.png

因此,当你将引用传入函数,并在函数中操作这个引用时,最后被修改的,还是值本身。

关于作用域,数据类型,更详细的解答,欢迎订阅我的书籍学习

https://xiaozhuanlan.com/afed

打印的还是let定义的'',和箭头函数没什么牵连呀。

撰写回答

登录后参与交流、获取后续更新提醒

宣传栏