# 三.ES6 知识点

# 1.var、let 及 const 区别

什么是提升?什么是暂时性死区?var、let 及 const 区别?

变量声明在函数之后,函数会被提升,并且优于变量提升

在全局作用域下letconst声明变量,变量不会被挂载到window上,再次声明之前声明的变量会报错,在声明之前使用变量也会报错(报错的原因就是暂时性死区)

# 2.原型继承和 Class 继承

原型如何实现继承?Class 如何实现继承?Class 本质是什么?

其实在 JS 中并不存在类,class只是语法糖,本质还是函数

calss Person{

}
Person instanceof Function // true
1
2
3
4

# 1.组合继承

function Parent(value) {
  this.val = value
}
Parent.prototype.getValue = function () {
  console.log(this.val)
}
function Child(value) {
  Parent.call(this, value)
}
Child.prototype = new Parent()
const child = new Child()

child.getValue() // 1
child instanceof Parent // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14

以上继承的方式核心是在子类的构造函数中通过Parent.call(this)继承父类的属性,然后改变了子类的原型为new Parent()来继承父类的函数。

这种继承方式的优点在于构造函数可以传参,不会与父类引用属性共享,可以复用父类的函数,但是也存在一个缺点就是在继承父类函数的时候调用了父类的构造函数,导致子类的原型上多了不需要的父类的属性,存在内存上的浪费。

# 2.寄生组合继承

function Parent(value) {
  this.val = value
}
Parent.prototype.getValue = function () {
  console.log(this.val)
}
function Child(value) {
  Parent.call(this.value)
}
Child.prototype = Object.create(Parent.prototype, {
  constructor: {
    value: Child,
    enumerable: false,
    writable: true,
    configurable: true,
  },
})
const child = new Child(1)
child.getValue() // 1
child instanceof Parent //true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

以上继承实现的核心就是将父类的原型赋值给了子类,并且将构造函数设置为子类,这样既解决了无用的父类属性问题,还能正确的找到子类的构造函数。

# 3.Class 继承

以上两种继承方式都是通过原型去解决的,在 ES6 中,我们可以使用class去实现继承,并且实现起来很简单

class Parent {
  constructor(value) {
    this.value = value
  }
  getValue(value) {
    console.log(value)
  }
}
class Child extends Parent {
  constructor(value) {
    super(value)
    this.val = value
  }
}
let child = new Child(1)
child.getValue() //1
child instanceof Parent // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

calss实现继承的核心在于使用extends表明继承来自哪个类,并且在子类构造函数中必须调用super,因为这段代码可以看成Parent.call(this,value)

当然了,之前也说了在 JS 中并不存在类,class的本质就是函数。

# 3.模块化

为什么要使用模块化?都有哪几种方式可以实现模块化,各有什么特点?

  • 基本概念:
    • 1.在 js 中,一个模块就是实现特定功能的文件(js)文件
    • 2.遵循模块的机制,想要什么就加载什么模块
    • 3.模块化开发需要遵循规范
  • js 实现模块化规范
    • 1.AMD 浏览器 requirejs 模块被异步加载,模块加载不影响后面语句的运行,默认使用 baseURL+paths 的路径解析方式
    • 2.CommonJS nodejs
    • 3.ES6 的 import/export
    • 4.CMD 浏览器端
  • 解决的问题:
    • 1.命名冲突
    • 2.文件依赖
    • 3.模块的复用
    • 4.提高代码可维护性,统一规范和开发方式

# 1.立即执行函数

在早期,使用立即执行函数实现模块化是常见的手段,通过函数作用域解决了命名冲突、污染全局作用域的问题

;(function (global) {
  global.test = function () {}
})(gloabl)
1
2
3

# 2.AMD 和 CMD

# 3.CommonJS

# 4.ES Module

ES Module 是原生实现的模块化方案,与 CommonJS 有以下几个区别

  • CommonJS 支持动态导入,也就是require(${path}/x.js),后者目前不支持,但是已有提案
  • CommonJS 是同步导入,因为用于服务器,文件都在本地,同步导入即使卡主主线程影响也不大。后者是异步导入,因为用于浏览器,需要下载文件,如果也采用同步导入会对渲染有很大影响。
  • CommonJS 在导出时都是值拷贝,就算导出的值变了,导入的值也不会改变,所以如果想要更新值,必须重新导入一次。但是 ES Modlues 采用实时绑定的方式,导入导出的值都指向同一个内存地址,所以导入值会跟随导出值变化
  • ES Modules 会编译成require/exports来执行

# 4.Proxy

Proxy 可以实现什么功能?

# 5.介绍下 Set、Map、WeakSet 和 WeakMap 的区别

  • Set
    • 成员的值都是唯一的,没有重复的值
    • 两个属性 constructor,size
    • 可以遍历
    • 四个方法:add,delete,has,clear
  • weakSet
    • 不重复的值的集合
    • 成员只能是对象,而不能是其他类型的值
    • 没有 size 属性,不能遍历
    • 三个方法 add,delete,has
  • Map
    • javascript 的对象,本质上是键值对的集合
    • 但是传统上只能用字符串当做键
    • 可以遍历,方法很多,可以干根各种数据格式转换
  • weakMap
    • 只接受对象作为键名
    • 键名指向的对象,不计入垃圾回收机制
    • 不能遍历,方法同 get,set,has,delete
上次更新: 2023/1/7 下午3:34:52