值传递应该是JS最基本的一个知识点了,网上也有不少说法,有按值传递,有按引用传递,还有按共享传递。what?javascript
我一直认为,学习应该去刨根问底。抓住他的核心点,找到事物的本质。因此在这里重新给你们梳理下。java
下面我先说下个人结论:学习
传递只有一种,就是
按值传递
按值传递
按值传递
,重要的事情要讲三遍哦。ui
标准规定,JavaScript 有 6种 基本类型,string
number
boolean
null
undefined
symbol
和Object
类型spa
咱们首先来看下,这七种类型在内存中是怎么分配的。3d
内存是分为栈区和堆区的code
当咱们声明6种基本类型的时候,就是在栈区开辟一段空间。cdn
当咱们声明一个Object类型的时候,在堆区和栈区各分配一段空间,堆区是Object声明的实体,栈区存放的是指向堆区的地址。对象
标准里面规定了,全部基本类型的值都是不可改变的。blog
var a = 1;
a = 2;
复制代码
你可能说不对吧,上面的代码,a就从1变成2了。
对,上面的变量a,确实变了。要理解上面那句话,咱们就须要明白 基本类型值自己
和 一个被赋值基本类型
的变量的区别。值不可更改,变量能够从新赋值。
下面咱们看一下,当咱们赋值的时候,内存中是怎么工做的。
当咱们声明 a 而且赋值为 1 的时候,栈区分配一段空间,值为1。
当咱们赋值为2的时候,并不会修改 1 所在空间,而是重新分配一段空间,值为 2,而且把这个赋值给变量 a。
上面的东西咱们都明白了,如今咱们再来看看按值传递是怎么回事。
第一种情形
var a = 1;
function getNum(p){
p = 10;
return p;
}
getNum(a) // 10
a // 1
复制代码
执行方法的时候,会把 a 的值,复制一份传递给形参 p。
因为 a 的值是 1 ,因此 p 的值也是 1。
第二种情形
var a = {
x: 1
}
function getNum(p){
p.x = 10;
console.log(p.x) // 10
}
getNum(a)
a.x // 10
复制代码
以上代码也是把 a 的值复制一份给 p。
只不过 a 的值比较特殊,他是一个指向堆区的内存地址,因此p的值也是一个指向同一个堆区的地址。
因此操做 p 的时候 a 也会跟着变化。由于这是在操做同一分内存。
第三种情形
var a = {
x: 1
}
function getNum(p){
p = 10;
console.log(p) // 10
}
getNum(a)
a.x // 1
复制代码
这个跟第二种也有点像,也是 a 的内存地址复制了一份给 p。
区别是对变量 p 重新赋值了。因此他的修改其实不会影响到 a 。
经过以上内容是否是就完全搞清楚了值传递究竟是怎么回事了。全部的传递方式其实都是按值传递,只不过有的值是基本类型,有的值是内存地址。
咱们再来延伸一下,ES6 出了一个新的声明变量的方式 const
。它能够声明一个常量,而且不能从新声明。也不能修改值。
咱们来看下:
const a = 100;
a = 200; // error
const b = {x:100}
b = {} //error
b.x = 200; //修改为功
复制代码
咱们经过今天的内存只是来分析下:
其实上const
锁死的是变量 a
,你在声明赋值以后他就锁定了那一块栈区的内存。当你赋值的时候其实就是换一块栈区内存空间,因此修改是无效的。
可是若是初始化值是一个对象,咱们知道在栈区它是一个内存地址。虽然咱们没法修改栈区,可是咱们能够修改地址对应的堆区的内容。这也是最后b.x = 200
可以修改为功的缘由。
当若是再有人问你 值传递
引用传递
的时候,你能够大声的告诉他,只有一种传递,值传递
啰里啰嗦的写了一堆,文笔很差望见谅。若是有错误或者不足之处,但愿你们指正。若是你读了以后,对你有一点点的帮助,不甚荣幸。