JavaScript内存机制

JavaScript内存机制

内存分配:

JavaScript在定义变量时就自动完成了内存分配:

//给数值变量分配内存
var num = 123

//给字符串分配内存  
var str = "abc"  

//给对象及其包含的值分配内存
var obj = {
  a: 1,
  b: null
}  

//给数组及其包含的值分配内存(就像对象一样) 
var ary = [1, null, "abc"]

//给函数(可调用的对象)分配内存
function fn(a){
  return a
} 

//函数表达式也能分配一个对象
element.addEventListener('click', function(){
  element.style.color = 'pink'
}, false)

有些函数调用结果是分配对象内存:

//分配一个Date对象
var date = new Date() 

//分配一个DOM元素
var ele = document.createElement('div')

有些方法分配新变量或者新对象:

//str2是一个新的字符串,因为字符串是不变量,JavaScript 可能决定不分配内存,只是存储了 [0-3] 的范围
var str1 = "abc"
var str2 = str1.substr(0, 3)

//新数组ary3有四个元素,是ary1连接ary2的结果
var ary1 = ["ab", "cd"]
var ary2 = ["ef", "gh"]
var ary3 = ary1.concat(ary2)

内存模型:

JS内存空间分为栈(stack)、堆(heap)、池(一般也会归类为栈中)

其中栈存放变量,堆存放复杂对象,池存放常量
基础数据类型的变量存储在栈中,引用数据类型的变量存储在堆中,引用数据类型的地址也存储在栈中
访问基础数据类型变量时,直接从栈中读取值
访问引用数据类型变量时,先从栈中读取引用数据类型指向的地址,再根据地址到堆中读取数据

基础数据类型和栈内存

js基础数据类型(简单数据类型):String,Number,Boolean,Null,Undefined

基础数据类型的变量指向的是栈内存中的值
JavaScript内存机制_第1张图片
当声明一个变量a时,会在栈内存里面分配一块存放变量a存储的值的内存,当变量a存储的值发生改变时,栈内存里面对应的a存储值的内存里的值也会发生相应改变,如果又声明了一个变量b,并把变量a的值赋值给变量b,此时在栈内存里面会新分配一块存放变量b存储的值的内存,a和b两个变量分别对应两块存储的值相同的栈内存,且两块栈内存互不影响

//将变量a的值赋值给变量b
var a = 1
var b = a
console.log(a) //1
console.log(b) //1

//改变变量a的值,变量b的值不受影响
a = 2
console.log(a) //2
console.log(b) //1

//改变变量b的值,变量a的值不受影响
b = 3
console.log(a) //2
console.log(b) //3

引用数据类型和堆内存

js引用数据类型(复杂数据类型):Object (Array,Date,Function …)

引用数据类型指向的是其在栈内存中的地址,通过这个地址,指向对应堆内存中的数据
JavaScript内存机制_第2张图片
当声明一个对象变量obj时,会在栈内存中分配一块存放obj地址的内存,堆内存中会分配一块内存存放地址指向的obj的数据,如果将obj赋值给另一个对象时,其实是把这个对象在栈内存中的地址传递给了另一个对象,他们共享地址指向的堆内存中的同一块内存和里面存放的数据,如果改变其中一个对象的一个属性,其对应的堆内存中的数据就会被改变,所以另一个对象中的属性也会被改变,如果对其中一个对象重新赋值,这个对象在栈内存中的地址就会指向另一块堆内存, 不再与另一个对象共享同一块堆内存,且两块堆内存互不影响

//将obj1的值赋值给obj2
var obj1 = {
    a: 1,
    b: 2
}
var obj2 = obj1
console.log(obj1) //{a:1, b:2}
console.log(obj2) //{a:1, b:2}

//改变obj1的属性值,obj2发生相应改变
obj1.a = 3
console.log(obj1) //{a:3, b:2}
console.log(obj2) //{a:3, b:2}

//将obj1重新赋值,obj2的值不受影响
obj1 = {
    a: 3,
    b: 4
}
console.log(obj1) //{a:3, b:4}
console.log(obj2) //{a:3, b:2}

浅拷贝和深拷贝

浅拷贝:

浅拷贝可以理解为,在栈内存中的拷贝行为,只能拷贝栈内存中的基本值和引用地址

//浅拷贝的简单实现
var obj1 = {
    a: 1,
    b: 2
}
var obj2 = obj1
console.log(obj1) //{a:1, b:2}
console.log(obj2) //{a:1, b:2}

//浅拷贝只是拷贝栈内存中的引用地址,两个变量共用同一堆内存中的数据
obj1.a = 3
console.log(obj1) //{a:3, b:2}
console.log(obj2) //{a:3, b:2}
深拷贝:

深拷贝可以理解为,同时在栈内存和堆内存中的拷贝行为,不仅拷贝栈内存中的基本值和引用地址,引用地址指向的堆内存中的数据也会被拷贝

//深拷贝的简单实现
var obj1 = {
    a: 1,
    b: 2
}
var obj2 = JSON.parse(JSON.stringify(obj1))
console.log(obj1) //{a:1, b:2}
console.log(obj2) //{a:1, b:2}

//深拷贝拷贝栈内存中的引用地址,也拷贝堆内存中的数据,两个变量拥有不同堆内存中的数据
obj1.a = 3
console.log(obj1) //{a:3, b:2}
console.log(obj2) //{a:1, b:2}

内存生命周期:

  1. 分配内存:当申明变量、对象、函数的时候,系统会自动完成内存的分配
  2. 使用内存:使用变量、对象、函数等分配到的内存(读,写)
  3. 回收内存:使用完毕,不需要时将内存释放归还
    JavaScript内存机制_第3张图片

你可能感兴趣的:(js)