原始类型(基本类型、不可变类型)
-
类型:number、string、boolean、null、undefined、symbol(ES6)
-
存储的是值,存放在栈内存
-
没有函数可以调用
undefined.toString()
'1'.toString()
//'1'已经不是原始类型,被强制转换成了String类型也就是对象类型
- 不能给基本类型的值添加属性
var name="Nicholas";
name.age=27;
alert(name.age); //undefined
- 复制变量时,复制的是值
var num1=5;
var num2=num1; //5
//num1和num2的5是完全独立的
- 传参时,参数按值传递,函数内部的操作不影响函数外部的变量
function fun(val){
val+=10;
return val;
}
var count=20;
fun(count); //30 不影响外部的count变量
console.log(count); //20
-
【坑】
number
类型是浮点类型的,在使用中会遇到某些 Bug,比如0.1 + 0.2 !== 0.3
-
【坑】
string
类型是不可变的,无论你在string
类型上调用何种方法,都不会对值有改变。 -
【坑】
typeof null
返回object
对象类型(引用类型、可变类型)
-
类型:对象Object、数组Array、函数
-
存储的是地址(指针),存放在堆内存
- 当需要访问引用类型的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。
-
在操作对象时,实际上是操作对象的引用而不是实际的对象。引用类型的值是按引用访问的。
-
可以给引用类型动态地添加属性
var person=new Object();
person.name="Nicholas";
alert(person.name); //"Nicholas"
- 复制变量时,复制的是指针
var obj1=new Object();
var obj2=obj1; //实际上obj1和obj2引用同一个对象
obj1.name="Nicholas";
console.log(obj2.name); //"Nicholas"
- 传参时,参数是按值传递,但是还会按引用来访问同一个对象,所以函数内部的操作会影响函数外部的实例
function fun(obj){
obj.name="xx";
return obj;
}
var person=new Object();
fun(person)
console.log(person); //{name:"xx"}
原始类型 VS 对象类型
存储的是 | 复制变量值 | 传递参数 | 在内存中存储方式 | |
---|---|---|---|---|
原始类型 | 值 | 复制值 | 不影响原来的变量 | 栈存储 |
对象类型 | 地址(指针) | 复制地址(指针) | 影响原来的变量 | 堆存储 |
【解析】
原始类型占据的空间是固定的,所以可将它们存储在较小的内存区域栈中,这样存储便于迅速查找变量的值。
由于引用类型值的大小会改变,所以不能将它放在栈中,否则会降低变量查询速度。
地址的大小是固定的,可以放在栈里。
【小结】在内存中存储方式不同导致了原始数据类型不可变,赋值是传值,引用数据类型赋值是传址。
栈和堆
栈(stack)会自动分配的内存空间,它由系统自动释放;
堆(heap)则是动态分配的内存,大小不定也不会自动释放。
区别 | 堆(heap) | 栈(stack) |
---|---|---|
空间分配 | 大小需要自己申请,并指明大小 | 系统自动分配释放 |
存储区 | 队列优先,先进先出(FIFO—first in first out) | 先进后出(FILO—First-In/Last-Out) |
缓存方式 | 二级缓存,生命周期由虚拟机的垃圾回收算法来决定 | 一级缓存,被调用时处于存储空间中,调用完毕立即释放。 |
申请效率 | 由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便. | 速度较快。但程序员是无法控制的。 |