1.原始值与引用值

  • 原始值: Undefined Null Boolean Number String Symbol Bigint 保存变量是按值访问的
  • 引用值: Object 操作对象的引用,保存变量是按引用访问的

1.1 动态属性

对于引用值,可以随时添加,修改,删除其属性和方法
原始值不能拥有属性 给原始值添加属性不会报错

  1. let person = new Object();
  2. person.name = "ming";
  3. console.log(person.name); //"ming"
  4. let name = "mming";
  5. name.age = 23;
  6. console.log(name.age); //undefined

1.2 复制值

通过变量把一个原始值赋给另一个变量时,原始值会被复制到新变量的位置
image.png

  1. let num1 = 5;
  2. let num2 = num1;

把引用值从一个变量赋给另一个变量时,存储在变量中的值也会被复制到新变量所在的位置

这里复制的值是一个指针,它指向存储在堆内存中的对象

image.png

  1. let obj1 = new Object();
  2. let obj2 = obj1;
  3. obj1.name = "ming";
  4. console.log(obj2.name); // "ming"

1.3 传递参数

所有函数的参数都是按值传递的

2.执行上下文与作用域

2.1 上下文

变量或函数的上下文决定了他们可以访问哪些数据,以及他们的行为。

在浏览器中,全局上下文就是windows对象,所有通过var定义的全局变量和函数会成为window对象的属性和方法。

上下文代码在执行的时候,会创建变量对象的一个作用域链,这个作用域链决定各级上下文中代码在访问变量和函数时的顺序。
代码正在执行的上下文的变量对象始终位于作用域链的最前端,如果上下文是函数,其活动对象用作变量对象。
image.png

  1. var color = "blue";
  2. function changeColor() {
  3. let anotherColor = "red";
  4. function swapColors() {
  5. let tempColor = anotherColor;
  6. anotherColor = color;
  7. color = tempColor;
  8. // 这里可以访问 color、anotherColor 和 tempColor
  9. }
  10. // 这里可以访问 color 和 anotherColor,但访问不到 tempColor
  11. swapColors();
  12. }
  13. // 这里只能访问 color
  14. changeColor();

这里面有全局上下文、changeColor()的局部上下文和 swapColors()的局部上下文。
内部上下文可以通过作用域链访问外部上下文中的一切,但外 部上下文无法访问内部上下文中的任何东西。

2.2变量声明

2.2.1 var

在使用 var 声明变量时,变量会被自动添加到最接近的上下文。
var 声明会被拿到函数或全局作用域的顶部,位于作用域中所有代码之前。

  1. var name = "ming";
  2. // 等价于:
  3. name = 'ming';
  4. var name;

通过在声明之前打印变量,可以验证变量会被提升。

  1. console.log(name); // undefined
  2. var name = 'ming';
  3. function() {
  4. console.log(name); // undefined
  5. var name = 'ming';
  6. }

2.2.2 let

ES6 新增的 let 关键字跟 var 很相似,但它的作用域是块级的

  1. if (true) {
  2. let a;
  3. }
  4. console.log(a); // ReferenceError: a 没有定义

let 与 var 的另一个不同之处是在同一作用域内不能声明两次。重复的 var 声明会被忽略,而重复的 let 声明会抛出 SyntaxError。

  1. var a;
  2. var a;
  3. // 不会报错
  4. {
  5. let b;
  6. let b;
  7. }
  8. // SyntaxError: 标识符 b 已经声明过了

2.2.3 const

使用 const 声明的变量必须同时初始化为某个值。一经声明,在其生命周期的任何时候都不能再重新赋予新值。

  1. const a; // SyntaxError: 常量声明时没有初始化
  2. const b = 3;
  3. console.log(b); // 3
  4. b = 4; // TypeError: 给常量赋值

3.垃圾回收

3.1 标记清理

当变量进入上下文,比如在函数内部声明一个变量时,这个变量会被加上存在于上下文中的标记。
当变量离开上下文时,也会被加上离开上下文的标记。

垃圾回收程序运行的时候,会标记内存中存储的所有变量。然后它会将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉。在此之后再被加上标记的变量就是待删除的了,原因是任何在上下文中的变量都访问不到它们了。随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存。

3.2 引用计数

每个值都记录它被引用的次数。

声明变量并给它赋一个引用值时,这个值的引用数为 1。如果同一个值又被赋给另一个变量,那么引用数加 1。类似地,如果保存对该值引用的变量被其他值给覆盖了,那么引用数减 1。当一个值的引用数为 0 时,就说明没办法再访问到这个值了,因此可以安全地收回其内存了。垃圾回收程序下次运行的时候就会释放引用数为 0 的值的内存。

3.3 性能

3.4 内存管理