Skip to content

ES6~ES13 新特性

只列常用的

词法环境

词法环境(Lexical Environment)是 JavaScript 中的一种内部机制,用于管理变量和函数的作用域。它是一个对象,包含了当前执行上下文中的所有变量和函数声明。

每个函数在创建时都会创建一个词法环境,用于存储函数内部的变量和函数声明。词法环境由两个部分组成:

  1. 环境记录(Environment Record):存储变量和函数声明的实际位置。
  2. 外部环境引用(Outer Environment Reference):指向外部词法环境,通常是创建该函数的外部函数的词法环境。

当 JavaScript 引擎查找变量时,会首先在当前词法环境中查找,如果找不到,则会沿着外部环境引用逐级向上查找,直到全局环境

不要和原型链混淆

只有在查找对象的属性时,才会涉及原型链的查找。

具体来说:

变量查找:先在当前词法环境中查找,如果找不到,则沿着外部词法环境逐级向上查找,直到全局环境。

对象属性查找:先在对象自身的属性中查找,如果找不到,则沿着对象的原型链逐级向上查找。

全局环境(Global Environment)。全局环境是最外层的词法环境,它包含了全局作用域中的所有变量和函数声明。

全局环境由以下两部分组成:

  1. 全局对象(Global Object):在浏览器中是 window 对象,在 Node.js 中是 global 对象。全局对象包含了所有全局变量和全局函数。
  2. 全局环境记录(Global Environment Record):存储全局变量和函数声明的实际位置。

当 JavaScript 代码在全局作用域中执行时,会创建一个全局环境。所有在全局作用域中声明的变量和函数都会被添加到全局环境中。

let、const

let 关键字:

  • 从直观的角度来说,let 和 var 没有太大区别,都用于声明变量

const 关键字:

  • 若赋值的是简单类型,则不能被修改
  • 若赋值的是引用类型,那么可以通过引用找到对应对象,修改对象内容

暂时性死区

暂时性死区是指在使用 letconst 声明变量时,从变量所在的词法环境被实例化到变量声明之间的这段时间内,变量是不可访问的。如果在这段时间内尝试访问变量,会抛出 ReferenceError 错误。

也就是说,代码在执行阶段,执行到该变量声明之前,该变量都是不可访问的

但其实,在代码编译阶段letconst 声明的变量,已经在环境记录中创建了一个条目,但区别于 var,let 和 const 的变量不会被初始化

所以,let、const 变量在声明之前不能被访问,称之为没有作用域提升

块级作用域

块级作用域是指在一个代码块(由 {} 包围的代码区域)内部声明的变量只能在该代码块内部访问。ES6 引入了 let 和 const 关键字来创建块级作用域。if 语句、for 循环等都可以创建块级作用域。

var、let 和 const 的区别是什么?

var 声明的变量具有函数作用域或全局作用域,没有块级作用域,且存在变量提升。

let 声明的变量具有块级作用域,没有变量提升,在声明之前访问会导致 ReferenceError

const 声明的变量具有块级作用域,没有变量提升,声明时必须初始化,且不能重新赋值。

Symbol

Symbol 值是通过 Symbol 函数来生成的,生成后可以作为属性名

Symbol 函数每次执行后的值都是独一无二的

那如果我们想创建相同的 Symbol 该怎么办

  • 可通过 Symbol.for 来创建相同值
  • 也可通过 Symbol.keyFor 来获取对应 key
js
const s1 = Symbol.for('abc')
const s2 = Symbol.for('abc')
console.log(s1 === s2) //true
const key = Symbol.keyFor(s1)
console.log(key) // abc

Set 和 WeakSet

Set 是一个新增的数据结构,可以用来保存数据,类似于数组,但是和数组的区别是元素不能重复

创建 Set 我们需要通过 Set 构造函数(暂时没有字面量创建的方式)

Set 有一个非常常用的功能就是给数组去重

Set 常见用法

  • 属性 size:返回 Set 中元素个数
  • add(value):添加某个元素,返回 Set 对象本身
  • delete(value):从 set 中删除和这个值相等的元素,返回 boolean 类型;
  • has(value):判断 set 中是否存在某个元素,返回 boolean 类型;
  • clear():清空 set 中所有的元素,没有返回值;

另外,Set 支持for of遍历

Set类似的另外一个数据结构称之为WeakSet,也是内部元素不能重复的数据结构。

Set的区别是

  • WeakSet 中只能存放对象类型,不能存放基本数据类型;
  • WeakSet 对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么 GC 可以对该对象进行回收

WeakSet 常见方法

  • add(value):添加某个元素,返回 WeakSet 对象本身
  • delete(value):从 WeakSet 中删除和这个值相等的元素,返回 boolean 类型;
  • has(value):判断 WeakSet 中是否存在某个元素,返回 boolean 类型;

WeakSet无法被遍历

WeakSet 的设计初衷是为了存储对象的弱引用,以便垃圾回收机制能够更有效地回收不再使用的对象。因此,WeakSet 不提供遍历其元素的方法。因为遍历操作需要保持对元素的强引用,这与 WeakSet 的设计目标相冲突。

Map 和 WeakMap

另外一个新增的数据结构是 Map,用于存储映射关系

Map 常用方法

  • 属性size:返回 Map 中元素的个数
  • set(key, value):在 Map 中添加 key、value,并且返回整个 Map 对象;
  • get(key):根据 key 获取 Map 中的 value;
  • has(key):判断是否包含某一个 key,返回Boolean类型;
  • delete(key):根据 key 删除一个键值对,返回Boolean类型;
  • clear():清空所有的元素;
  • Map 也可以通过 for of 进行遍历。

WeakMapMap 的区别

  • 区别一:WeakMap 的 key 只能使用对象,不接受其他的类型作为 key;
  • 区别二:WeakMap 的 key 对对象的引用是弱引用,如果没有其他引用引用这个对象,那么 GC 可以回收该对象;

Map 和 Object 的区别

  1. 键的类型:
  • 对象的键只能是字符串或 Symbol。
  • Map的键可以是任意类型,包括对象、函数、基本类型等。
  1. 键值对的顺序:
  • 对象的键值对没有顺序。
  • Map的键值对是有序的,按照插入顺序进行迭代。
  1. 迭代:
  • 对象需要手动获取键数组然后迭代。
  • Map可以直接迭代,支持 for...of 循环。
  1. 性能:
  • Map在频繁增删键值对的场景下性能更好。
  • 对象在频繁增删键值对时性能较差。
  1. 默认键:
  • 对象有一些默认的键(如 __proto__)。
  • Map没有默认的键,所有键都是显式添加的。
  1. 大小:
  • 对象没有内置的属性来获取大小。
  • Mapsize 属性来获取键值对的数量。

Proxy

如果我们希望监听一个对象的相关操作,那么我们可以先创建要给代理对象(Proxy对象)

  • 首先,我们需要 new Proxy 对象,并且传入需要侦听的对象以及一个处理对象,可以称之为 handler
js
const p = new Proxy(target, handler)
  • 其次,我们之后的操作都是直接对 Proxy 的操作,而不是原有的对象,因为我们需要在 handler 里面进行侦听;

相比于 Object.defineProperty 只有 set, get 属性描述符来监听对象,Proxy 有多达 13 种捕捉器(Trap

Reflect

Reflect 也是 ES6 新增的一个 API,它是一个对象,字面的意思是反射

它提供了很多操作 Javascript 对象的方法,有点像 Object 中操作对象的方法

尽管 ReflectObject 都提供了一些相似的方法,但它们的设计目标和用途有所不同。Reflect 更加注重与 Proxy 的集成和一致性,而 Object 更加注重对象的创建和属性操作。