Javascript高级之变量、作用域与内存

变量、作用域与内存

原始值与引用值

  • 理解要点

    • ECMAScript中所有函数的参数都是按值传递的
    • 函数外的值会被复制到函数内部的参数中
    • 关于引用值(对象),也是按值传递的
      • 理解
        • 对象中保存的值是对象的key,也就是指针
        • 函数中按值传递时,可以给指针赋值,影响全局变量
        • 但是改变不了对象的key
        • 可以用对象的动态属性来理解
  • 确定类型

    • 如果变量是给定引用类型的实例,则instanceof操作符返回true
    • 如果用instanceof检测原始值,则始终会返回false
let obj= null;
let obj2= {};
let fun= Function.prototype;
let fun2= new Function();
let arr= [];
let str= '';
let reg= new RegExp();
let date= new Date();

console.log(obj instanceof Object);     // false
console.log(obj2 instanceof Object);    // true
console.log(fun instanceof Function);   // false
console.log(fun2 instanceof Function);  // true
console.log(arr instanceof Array);      // true
console.log(str instanceof String);     // false
console.log(reg instanceof RegExp);     // true
console.log(date instanceof Date);      // true

执行上下文与作用域

  • 执行上下文

    • 每个上下文都有一个关联的变量对象
    • 所有变量和函数都存在于这个对象上
    • 这个对象就是上下文栈,在其所有代码执行完毕之后,就会被销毁
    • var定义的全局变量和函数,会成为window对象的属性和方法
  • 作用域链

    • 上下文中的代码在执行的时候,会创建变量对象的一个作用域链
    • 作用域链决定了各级上下文中的代码在访问变量和函数时的顺序
    • 如果上下文是函数,则其活动对象用作变量对象
    • 活动对象最初只有一个定义变量:arguments
      • arguments是包含函数形参的一个对象
      • 全局上下文没有这个变量
  • 作用域链增强

    • 在作用域链前端添加一个变量对象
      • with语句
        • 会向作用域链前端添加指定的对象
      • try/catch语句中的catch块
        • 会创建一个新的变量对象,这个变量对象会包含要抛出的错误对象的声明

变量声明

  • 使用var的函数作用域声明

    • 变量会被自动添加到最接近的上下文
    • 未声明的变量,会自动被添加到全局上下文
    • var声明会被拿到函数或全局作用域的顶部,叫做提升
  • 使用let的块级作用域声明

    • 块级作用域由最近的一对包含花括号{}界定
    • let在同一作用域内不能声明两次
    • let非常适合在循环中声明迭代变量
  • 使用const的常量声明

    • const声明的变量必须同时初始化为某个值
    • const声明只应用到顶级原语或者对象
    • 使用Object.freeze()给对象赋值常量

垃圾回收

  • 标记清理

    • 先给当前不使用的值加上标记,再回来回收它们的内存
  • 引用计数

    • 对每个值都记录它被引用的次数
    • 当引用次数为0时,垃圾回收程序会释放引用数为0的值的内存
  • 循环引用

    • 对象A有一个指针指向对象B,而对象B也引用了对象A
    • 只要涉及COM对象,就无法避免循环引用的问题

内存管理

  • 解除引用

    • 如果数据不再必要,那么把它设置为null,从而释放其引用
  • 通过const和let声明提升性能

    • 块作用域比函数作用域更早让垃圾回收程序介入
  • 隐藏类和删除操作

    • 在构造函数中一次性声明所有的属性,因此实例共享隐藏类
    • 把不想要的属性设置为null,可以保持隐藏类不变和继续共享
  • 内存泄漏

    • 没有使用关键字声明变量
    • 定时器的回调通过闭包引用了外部变量
    • 闭包造成的内存泄漏
  • 静态分配和对象池

    • 避免动态分配操作
posted @ 2020-12-19 18:42  wing1377  阅读(56)  评论(0编辑  收藏  举报