精简《JavaScript高级程序设计》四 、变量,作用域,内存问题
精简《JavaScript高级程序设计》四 、变量,作用域,内存问题
第四章概况
4.1基本类型和引用类型的值
4.2执行环境及作用域
4.3垃圾收集
4.1基本类型和引用类型
ES变量包含基本类型值和引用类型值
基本类型指的是简单的数据段,包括Undefined、Null、Boolean、Number、String
引用类型值指的是那些可能由多个值构成的对象,包括Object,可以添加属性和方法
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型
复制变量值
对于基本类型而言,如果从一个变量向另一个变量复制,会在变量对象上创建一个新值,然后将该值复制到为新变量分配的位置
var a = 1
var b = a
对于引用类型而言,同样也会复制一份放到为新变量分配的空间中,不同的是这个值实际上是一个指针,指针指向存储在堆中的一个对象,复制结束后,两个变量实际上引用了同一个对象
var obj1 = new Object()
var obj2 = obj1
obj1.name = "fur"
console.log(obj2.name) //fur
传递参数
注意:访问变量有按值和按引用两种方式,而参数只能按值传递。
传递基本类型时会把值复制给一个局部变量(命名参数),传递引用类型时会把这个值在内存在的地址复制给一个局部变量,因此这个局部变量的变化会反映函数外部
function add(num){
num +=10
return num
}
var count = 20
var result = add(count)
console.log(result)//30
console.log(count)//20
因此基本类型不会印象函数外部的count变量,但是引用类型会改变
function setNum(obj){
obj.num =30
}
var count = new Object()
count.num = 20
setNum(count);
console.log(count.num)//30
很多人错误理解为引用类型的参数是引用传递,其实是按值传递的,再看修改后的代码
function setNum(obj) {
obj.num = 30
console.log(obj) //Object { num: 30 }
obj = new Object()
obj.num = 40
console.log(obj) //Object { num: 40 }
}
var count = new Object()
count.num = 20
setNum(count);
console.log(count) //Object { num: 30 }
console.log(count.num) //30
如果count是引用类型传递,那么count就会自动被修改为指向40,所以证明是值传递,实际上,函数内部重写obj,这个变量引用就是一个局部对象,函数执行完立即销毁。
书里这个地方说得有点理所当然,所以又找了找别的解释:
关键在于obj = new Object()
则会个地方会覆盖obj保存的指向count的地址值,使其指向新地址,那么此时的obj已经是一个局部变量,而且地址的改变使你无论对它进行什么操作都不会影响到原来的obj上面来。
检测类型
typeof:适用于检测基本类型
instanceof:适用于检测引用类型
var name = "fur"
var u
var n = null
var o = new Object()
console.log(typeof name)//string
console.log(typeof u)//undefined
console.log(typeof n)//object,这个需要注意
console.log(typeof o)//object
instanceof:适用于检测引用类型
var arr = new Array()
var o = new Object()
console.log(arr instanceof Array)//true
console.log(arr instanceof Object)//true 因为Object包括Array
console.log(o instanceof Array)//false
console.log(arr instanceof Object)//true
4.2执行环境及作用域
执行环境定义了变量或函数有权访问的其他数据,决定它们自身的行为,每个执行环境都有与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象里。
作用域链:保证对执行环境有权访问的所有变量和函数的有序访问,即可以访问自己以及自己父级以上的变量
通过代码说明
var name = "fur"
function changeName(){
if(name === "fur"){
name = "fur1"
}else{
name = "fur2"
}
}
changeName();
console.log(name)//fur1
由此,changeNamed的作用域链包括自己的变量对象和全局环境的变量对象。
没有块级作用域,这个专指var,作用域只能限制在函数内,而无法像Java一样限制在块级内,但是ES6已经出现了let和count两种新的声明变量的方法,可以实现块级作用域,let可以修改,count不可修改
4.3垃圾收集
JavaScript具有自动垃圾收集机制
原理:找到不再使用的变量,释放其内存,垃圾收集器会按照固定的时间间隔周期性执行,方式主要有标记清理
标记清除:变量进入环境打上标记“进入环境”,离开环境打上标记“离开环境”
管理内存
接触引用:数据不在用,可以将其值设置为null,用于全局变量和对象,局部的离开执行环境会被自动解除引用。
注意:解除引用不等于回收该值所占内存,还是需要等待垃圾收集器
码字不易,有用的话点个赞鸭!