1.原始值与引用值
- 原始值: Undefined Null Boolean Number String Symbol Bigint 保存变量是按值访问的
- 引用值: Object 操作对象的引用,保存变量是按引用访问的
1.1 动态属性
对于引用值,可以随时添加,修改,删除其属性和方法
原始值不能拥有属性 给原始值添加属性不会报错
let person = new Object();
person.name = "ming";
console.log(person.name); //"ming"
let name = "mming";
name.age = 23;
console.log(name.age); //undefined
1.2 复制值
通过变量把一个原始值赋给另一个变量时,原始值会被复制到新变量的位置
let num1 = 5;
let num2 = num1;
把引用值从一个变量赋给另一个变量时,存储在变量中的值也会被复制到新变量所在的位置
这里复制的值是一个指针,它指向存储在堆内存中的对象
let obj1 = new Object();
let obj2 = obj1;
obj1.name = "ming";
console.log(obj2.name); // "ming"
1.3 传递参数
所有函数的参数都是按值传递的
2.执行上下文与作用域
2.1 上下文
变量或函数的上下文决定了他们可以访问哪些数据,以及他们的行为。
在浏览器中,全局上下文就是windows对象,所有通过var定义的全局变量和函数会成为window对象的属性和方法。
上下文代码在执行的时候,会创建变量对象的一个作用域链,这个作用域链决定各级上下文中代码在访问变量和函数时的顺序。
代码正在执行的上下文的变量对象始终位于作用域链的最前端,如果上下文是函数,其活动对象用作变量对象。
var color = "blue";
function changeColor() {
let anotherColor = "red";
function swapColors() {
let tempColor = anotherColor;
anotherColor = color;
color = tempColor;
// 这里可以访问 color、anotherColor 和 tempColor
}
// 这里可以访问 color 和 anotherColor,但访问不到 tempColor
swapColors();
}
// 这里只能访问 color
changeColor();
这里面有全局上下文、changeColor()的局部上下文和 swapColors()的局部上下文。
内部上下文可以通过作用域链访问外部上下文中的一切,但外 部上下文无法访问内部上下文中的任何东西。
2.2变量声明
2.2.1 var
在使用 var 声明变量时,变量会被自动添加到最接近的上下文。
var 声明会被拿到函数或全局作用域的顶部,位于作用域中所有代码之前。
var name = "ming";
// 等价于:
name = 'ming';
var name;
通过在声明之前打印变量,可以验证变量会被提升。
console.log(name); // undefined
var name = 'ming';
function() {
console.log(name); // undefined
var name = 'ming';
}
2.2.2 let
ES6 新增的 let 关键字跟 var 很相似,但它的作用域是块级的
if (true) {
let a;
}
console.log(a); // ReferenceError: a 没有定义
let 与 var 的另一个不同之处是在同一作用域内不能声明两次。重复的 var 声明会被忽略,而重复的 let 声明会抛出 SyntaxError。
var a;
var a;
// 不会报错
{
let b;
let b;
}
// SyntaxError: 标识符 b 已经声明过了
2.2.3 const
使用 const 声明的变量必须同时初始化为某个值。一经声明,在其生命周期的任何时候都不能再重新赋予新值。
const a; // SyntaxError: 常量声明时没有初始化
const b = 3;
console.log(b); // 3
b = 4; // TypeError: 给常量赋值
3.垃圾回收
3.1 标记清理
当变量进入上下文,比如在函数内部声明一个变量时,这个变量会被加上存在于上下文中的标记。
当变量离开上下文时,也会被加上离开上下文的标记。
垃圾回收程序运行的时候,会标记内存中存储的所有变量。然后它会将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉。在此之后再被加上标记的变量就是待删除的了,原因是任何在上下文中的变量都访问不到它们了。随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存。
3.2 引用计数
每个值都记录它被引用的次数。
声明变量并给它赋一个引用值时,这个值的引用数为 1。如果同一个值又被赋给另一个变量,那么引用数加 1。类似地,如果保存对该值引用的变量被其他值给覆盖了,那么引用数减 1。当一个值的引用数为 0 时,就说明没办法再访问到这个值了,因此可以安全地收回其内存了。垃圾回收程序下次运行的时候就会释放引用数为 0 的值的内存。