推荐的最佳实践

  • 初始化变量之前一定要先声明变量 — 推荐使用let const
  • 访问局部变量比访问全局变量要快
  • 全局对象使用之后置为null

    原始值和引用值

  • 原始值:Undefined、Null、Boolean、Number、String 和 Symbol。保存原始值的变量是按值

  • 对象: 保存引用值的变量是按引用
  • 属性的添加:原始值不能有属性,尝试给原始值添加属性不会报错,但是会得到undefined,也就是添加失败。只有引用值可以添加属性。

    1. let name = "Nicholas";
    2. name.age = 27;
    3. console.log(name.age); // undefine
  • 在赋值时: 值的贮存是完全独立的,赋值后可以独立使用。引用的赋值,是赋值指针,会指向同一个位置。

    1. let obj1 = new Object();
    2. let obj2 = obj1;
    3. obj1.name = "Nicholas";
    4. console.log(obj2.name); // "Nicholas"
  • 在传递参数时:值会被赋值到一个局部变量中。传递参数的时候,引用也是按值传递的。 (函数的参数就是局部变量,所以是单独的一个变量)

    1. function setName(obj) {
    2. obj.name = "Nicholas";
    3. obj = new Object();
    4. obj.name = "Greg";
    5. }
    6. let person = new Object();
    7. setName(person);
    8. console.log(person.name); // "Nicholas" , 这里的obj.name,并没有是"Greg"
  • 确定类型时:值用typeof就可以判断,对象需要用instanceof,判断是否是那个对象的实例,值使用instanceof会始终返回false;

    上下文和作用域

  • 上下文决定了,在哪里可以使用变量活动对象。

  • 函数有单独的上下文,在函数执行的时候,进入到函数上下文栈中,结束后弹出当前上下文,回到之前的上下文。 函数参数被认为是当前上下文中的变量
  • 声明变量使用const let
  • 标识符查找,从内向外, 所以: 访问局部变量比访问全局变量要快

    垃圾回收

    确定哪个变量不会再 使用,然后释放它占用的内存, 是js语言自动执行的,一般使用标记清理和引用计数这两种策略。常用策略:标记清理

标记清理

  • 给程序所有的内容打上标记,然后把使用到的标记清除掉。然后回收带有标记的内容

    引用计数

  • 用到了加1,不用减1,为0清除。

  • 循环引用,会一直在内存里。所以使用的不多
  • 可以用设置为null来切除引用

    内存管理

  1. 如果数据不再必要,那么把它设置为 null,从而释放其引用。这也可以叫作解除引用。这个建议最适合全局变量和全局对象的属性
  2. 使用const 和 let 在专属的块中使用,可以更快的触发垃圾回收
  3. 减少隐藏类的生成 —- 删除和动态赋值属性会产生隐藏类。所以最好使用null进行解除引用。并且一开始就声明好类中的属性。
  4. 内存泄露: 意外声明全局变量,定时器产生的闭包,闭包 —- 容易产生内存泄露
  5. 静态分配与对象池 —- 不推荐使用