JavaScript高程学习笔记(二)

117 阅读7分钟

4. 变量、作用域与内存

4.1 原始值与引用值

  • 保存原始值的变量时是按值访问的;值存储于栈中;复制时复制了值的副本,参数传递亦是如此。
  • 保存引用值的变量是是按引用访问的;值存储于堆中;复制时复制了引用地址,参数传递亦是如此。

4.2 执行上下文与作用域

执行上下文:决定了变量和函数可以访问哪些数据以及他们的行为,都有一个关联的变量对象。变量对象存储了指向上下文中定义的所有变量的函数(供内部使用)。

  • 全局上下文,最外层的上下文。在浏览器这个宿主环境中即为window对象。
    • 通过var定义的全局变量的和函数都会称为window的属性和方法。
    • 全局上下文在应用程序退出前才会被销毁(比如网页关闭,退出浏览器)
  • 函数上下文,当代码执行流进入函数时,函数的上下文被推入执行上下文堆栈。函数执行完毕后弹出。
    • 程序的执行流通过这个上下文堆栈来控制。

上下文执行代码:执行时创建变量对象的一个作用域链,该作用域链决定了各级上下文中的代码在访问变量和函数的顺序。代码正在执行的上下文的变量对象始终位于作用域链的最前端。 如果上下文是函数,其活动对象(活动对象是最初只有一个定义变量:arguments)用作变量对象。作用域链的下一个变量对象来自包含上下文,在下一个对象来自再下一个包含上下文...一直到全局对象。

代码执行时标识符的解析沿作用域链逐级搜索,从作用域链的前端开始,直到找到或者(最终查到全局也未找到)未找到报错。

作用域链增强

  • 原理:在作用域链的前端临时添加一个上下文,这个上下文在代码执行后会被删除。
  • 方式:try/catch语句的catch块;with语句。

4.3 垃圾回收

执行环境负责在代码执行时管理内存。

  • 基本思路:确定哪个变量未使用,释放它占用的内存。
  • 特性:周期自动运行。
  • 标记策略:标记清除和引用计数清除。
    • 标记清除:变量进入上下文会被加上标记,变量离开上下文会被加上离开上下文的标记。而垃圾回收程序运行时会标记内存中存储的所有变量,然后会将在上下文中的变量,以及被上下文中的变量引用的变量的标记去掉。此后有标记的就是待删除的。随后垃圾回收程序做内存清理,销毁带标记的所有值并回收它们的内存。
    • 引用计数:对每个值记录它被引用的次数,引用值为0的即为待回收的。
      • 问题:循环引用,A对象中有指针指向B,B对象中有引用指向A。内存会被一直占用无法释放。
      • 解决:切断关联,设置为null。
  • 性能:优化方式通过动态改变分配变量、字面量或数值槽位等会触发垃圾回收的阈值,来避免频繁进行垃圾回收。
    • 回收程序回收的内存不到已分配的15%,增加阈值。
    • 回收程序回收的内存达到已分配的85%,阈值重置。
  • 内存管理:为了优化内存占用,需要在数据不再使用时设置为null,从而可以释放其引用-解除引用。
    • 尽量使用let const其为块级作用域,方便更早回收。
    • 隐藏类和删除操作:运行环境有时会根据使用的js引擎来采取不同性能优化策略。V8在将解释后的JavaScript代码编译为实际的机器码时会利用’隐藏类‘。运行期间V8会将创建的对象与隐藏类关联起来以跟踪它们的属性特征。能共享相同的隐藏类的对象性能更好。
    function Article() { this.title = 'foo'};
    let a1 = new Article();
    let a2 = new Article();
    // V8 会在后台让这个两个实例共享相同的隐藏类。
    a2.author = 'jack'; // 此时会打破共享不建议。
    // 优化方式
    function Article(author) { this.title = 'foo'; this.author = author};
    let a1 = new Article();
    let a2 = new Article('jack');
    delete a1.author; // 此时会打破共享不建议。
    // 优化方式
    a1.author = null;
    
    • 内存泄露:
      1. 意外声明全局变量
      2. 定时器,定时器回调通过闭包引用了外部变量。
      3. 使用闭包

5. 基本引用类型

引用值(或者对象)是某个特定引用类型的实例,在ECMAScript中,引用类型是把数据和功能组织到一起的结构。 对象被认为是某个特定引用类型的实例。

5.1 Date

Date类型将日期保存为自协调世界时间1970年1月1日午夜(零时)至今所经过的毫秒数。

创建当前日期通过new操作符调用Date构造函数,如果创建其它日期则需要传入毫秒数,因此ECMAScript提供了两个辅助方法Date.parse()和Date.UTC(),接收格式化的字符串或多参数并返回毫秒数。实际调用Date()时传入格式化字符串或者多参数会自动调用对应方法处理为毫秒数。

let d1 = new Date(Date.parse('May 23, 2019')) // 等同下面
let d11 = new Date('May 23, 2019')  //内部调用Date.parse

let d2 = new Date(Date.UTC(2000, 0)) // 等同下面
let d22 = new Date(2000, 0)  //内部调用Date.parse
  • 继承的方法:toLocaleString、toString、valueOf,进行了重写。
  • 日期格式化方法:toDateString、toTimeString、toLocalDateString、toLocalTimeString、toUTCString
  • 日期/时间组件方法:getTime、getFullYear、getMonth、getDate、getDay...

5.2 RegExp

  • 匹配模式标记:g i m y u s
  • 实例属性:global ignoreCase unicode sticky lastIndex muiltiline dotAll source flag
  • 实例方法:exec test
  • 构造函数属性:其它语言称为静态属性,input:$- lastMatch:$& lastParen$+ leftContext:$` rightContext:$' 还有$1~$9

5.3 原始包装类型

使用原始值的方法或属性时,后台会创建相应的原始包装类型对象,从而可以暴露操作原始值的各种方法。 创建的原始包装对象只存在于访问它的那行代码执行期间,离开该作用域会被销毁。

  • Boolean
  • Number:toFixed() toExponential() toPrecision()
  • String:charAt() fromCharCode() codePointAt() fromCodePoint()
    • 字符串操作方法:slice substring substr indeOf lastIndeOf startsWith endWith includes trim reapt padStart padEnd toLowerCase toUpperCase match search replace split localCompare

5.4 单例内置对象

  • Global
    • URL编码:encodeURI encodeURIComponent
    • eval方法:就是一个完整的解释器。接收一个要执行的字符串参数。
    • Global对象属性:undefined Infinity Object Array Function...
    • window对象
  • Math
    • 对象属性:E LN10 PI ...
    • 方法:min max random abs exp pow...

6. 集合引用类型

6.1 Object

属性通过点或者中括号存取。

6.2 Array

  • 创建数组:字面量、Array构造函数、静态方法from()和of();from接收第二个参数为函数可以增强新数组。
  • 数组空位:map跳过空位,输出undefined;join视空位为空字符串。
  • 检测数组:instanceof 静态方法isArray()
  • 迭代器方法:keys() values() entries()
  • 复制填充方法:fill copyWith
  • 栈队列方法:push pop shift push
  • 排序方法:reverse sort
  • 操作方法:slice concat splice
  • 查找方法:indexOf lastIndexOf find findInde
  • 迭代方法:every some forEach map filter
  • 归并方法:reduce reduceRight

6.3 定型数组

6.4 Map

键值存储机制。 方法属性:get set delet clear size

6.5 WeakMap

弱映射,键只能是对象,该键不属于正式的引用,不会阻止垃圾对其回收。

6.7 Set

集合数据结构。 方法属性:add has delete clear size

6.8 WeakSet

弱集合,值只能是对象,值不属于正式的引用,不会阻止垃圾对其回收。