4.1 原始值和引用值
ECMAScript变量包含两者不同类型的数据:
原始值:最简单的数据
引用值:多个值构成的对象
JS不允许直接访问内存位置,所以操作对象时,实际上时对该对象的引用而非对象本身
4.1.1 动态属性
let name1 = "M"// 在JS中 字符串被视为原始值
let name2 = new String('n')
name1.age = 10// 原始值不允许有动态属性,虽然不会报错
name2.age = 20// 引用值可以动态添加属性
console.log(name1.age);// undefined
console.log(name2.age);// 20
console.log(typeof name1);// String
console.log(typeof name2);// object
4.1.2 复制值
原始值指向不同值
引用值指向同一个对象(有点类似于python中可变类型的关系)
4.1.3 传递参数
ESMAScript中所有函数参数都是按值传递
但如果传入的是一个对象,不会发生把对象改变的情况
原因:当对象在函数内部被重写时,它变成了一个指向本地对象的指针,而本地对象在函数结束时就被销毁了
所以,可以说ESMAScript中所有参数都是局部变量
4.1.4 确定类型
typeof 可以很好的判断一个变量是不是原始类型
但是却不能很好的作用于引用类型,因为我们通常想知道引用类型是什么类型的对象
对于判断引用类型 使用 instanceof
colors instanceof Array
pattern instanceof RegExp
4.2 执行上下文与作用域
上下文代码在执行会创建变量对象的一个作用域链,决定访问变量和函数时的顺序
函数参数被认为是当前上下文中的变量
4.2.1 作用域增强
在碰到 try/catch和with的时候,会作用域链前面添加一个新的变量对象
4.2.2 变量声明
1.var会被自动添加到最接近的上下文
2.const/let 都属于块级作用域
3.标识符查找 从当前作用域一直往上找,找到的第一个就是
let color = 'red'
function getcolor(){
let color = 'blue'
{
let color = 'green'
return color
}
}
console.log(getcolor());// green
4.3 垃圾回收
js会在代码执行时管理内存
垃圾回收必须跟踪标记哪个变量还会使用,主要有两种方法
4.3.1 标记清理
js最常使用的垃圾回收策略,当变量进入上下文时,加上存在上下文的标记.当离开上下文时,加上离开上下文的标志
删除策略:垃圾回收程序会把内存中所有变量标记,然后去除所有上下文中的变量和上下文变量引用的变量去掉,剩下的就是等待回收的变量
4.3.2 引用计数
不常用
给每一个变量创建时标记1,当他被赋另一个引用值时把值+1,被覆盖时-1,当值为0时就可以安全的回收了
4.3.3. 性能
垃圾回收程序会根据运行时的环境勘探开决定何时运行
在某些浏览器中是支持手动垃圾回收(但是不推荐)
4.3.4 内存管理
1.使用const和let提升性能
2.隐藏类和删除操作
能够共享隐藏类的对象性能会更好,V8会根据这种情况优化
3.内存泄漏
可能产生于书写格式不合规,定时器,JavaScript闭包
4.43.4 静态分配与对象池
浏览器决定何时进行垃圾回收的一个标准就是对象的更替速度,如果很多对象被初始化,然后一下子又超出了作用域,浏览器就会采取更加激进的方式进行垃圾回收,这也会影响性能
解决方法:不动态创建对象
function addVector(a,b){
let resultant = new Vector();
resultant.x = a.x + b.x
resultant.y = a.y + b.y
return resultant
}
// 修改成如下形式
function addVector(a,b,resultant){
resultant.x = a.x + b.x
resultant.y = a.y + b.y
return resultant
}
另一种方法是对象池,在初始化时,可以创建一个对象池,用来管理一组可以回收的对象,在请求完后会归还,由于没有初始化,就没有对象更替,回收的频率也会降低,可以通过数组实现