基本数据类型和复杂数据类型的本质区别
数据类型
JavaScript中的数据类型可以分为两大类:
- 原始值 (基本类型)
- Boolean
- Null
- String
- Number
- Bigint
- Symbol
- Undefined
- 对象 (复杂类型)
- Object
- Array
- Function
小结:数据分为两大类,对象和非对象
数据的存放
数据存放在内存里面,内存分:栈区(stack),堆区(heap)。
栈区
栈区的特点是:数据按顺序存放,内存大小由系统分配。
基本类型的存放示意图:
堆内存
堆内存的特点是:数据随机存放,大小由程序员分配。
复杂类型的存放示意图:
行为差异
赋值
基本类型赋值
var a = 1
var b = a
b = 0
console.log(a) // 1
在栈内存中的数据发生复制行为时,系统会自动为新的变量分配一个新值。var b = a执行之后,a与b虽然值都等于1,但是他们其实已经是相互独立互不影响的值了,所以我们修改了b的值以后,a的值并不会发生变化。
复杂数据类型
var o1 = {name:"o1"}
var o2 = o1
o2.name = "o2"
console.log(o1.name)// o2
求值策略
所谓求值策略也就是函数的传参方式,函数的参数可能是基本类型也可能是复杂类型,这两种类型在传参的时候有所区别。
按值传递
按值传递,参数的值是调用者传递的值的拷贝(copy of value),函数内部改变参数的值不会影响到外面的值,一般来说,是重新分配了新内存,该新内存块的值是外部值的拷贝,并且它的值是用到函数内部的。
var a = 1
function changeA (a) {
a = 2
}
changeA()
console.log(a)// 1
这说明了,函数内部的a和函数外部的a是相互独立的,传参是将值拷贝一份。
那么对于复杂类型的传参呢。网上有各种各样的教程和文章,有的说按引用传递,什么共享传递,等等,其实很简单的道理,明白了上面的内存的分配,就很清楚的知道是怎么回事了,至于是叫按共享传递(Call by sharing)还是什么其他的都不重要。
还是按值传递
对于基本类型已经搞清楚了,传参的方式是按值传递,现在看复杂类型的传参:
总结:在函数传参的时候,不管是基本类型还是复杂类型,都是按值传递,对于基本类型是拷贝值也就是数据本身,而对于复杂类型,拷贝的是复杂类型在堆内存中的地址。