你不够重视的ES重点API细节(持续更新,欢迎评论补充)

171 阅读4分钟

let、const、var区别及特点

​ let、const、var的区别除了平时使用常见的作用域及赋值不同、var会有所在作用域内的变量提升外,let和const还有以下几个比较细节的特点:

  1. let和const都会造成暂时性死区;
  2. const对于简单类型数据(数值、字符串、布尔值)的值保存在变量指定的内存地址,等同于常量。但对复合型数据(主要是对象和数组),变量指向的内存地址保存的只是一个指针,const只能保证这个指针是固定的,但它的数据结构是否是可变的,则不受控制。顾不能用const声明一个不可变的数组或不可变的对象。
  3. let和const会存放在块级作用域内,var是全局可访问的。

作用域和作用域链

作用域是管理变量的一套规则,规定如何查找变量。在JS中,有三种作用域:全局作用域、函数作用域、块级作用域

常见的作用域工作模型有两种:词法作用域、动态作用域JS使用的是“词法作用域”

因为作用域是可以嵌套的,比如可以在函数中调用函数,就会产生嵌套作用域,多个嵌套作用域就组成了作用域链。

查找一个变量时,就会在作用域中查找,查找顺醋是由内向外,即先在当前作用域中查找,有则返回,没有则向上一级作用域查找,知道找到结果或找不到结果报错。

JS代码并非一行一行执行,也会有变量提升、函数提升。把这种提升现象理解为“一段一段”执行,每一段就是“可执行代码片段”。

在JS中,执行代码分为全局代码****和函数代码两种。当执行流进入可执行片段前,会做一些准备工作,这个工作就是创建执行上下文(也称执行环境),每个执行上下文都有两个中药属性:变量对象作用域链**。

箭头函数与普通函数的区别

  1. 普通function函数的声明在变量中是最高的,箭头函数没有函数提升;
  2. 箭头函数没有this、arguments;
  3. 箭头函数不能作为构造函数,不能被new,没有property;
  4. call和apply方法只有参数,没有作用域。

改变this指向,apply、call和bind三者的区别

  • call和apply都是为了改变某个函数运行时的执行上下文(context)而存在的,就是为了改变函数体内部的this指向。
  • call需要把参数按顺序传递过去,call则是把参数放到数组中传递。

Fun.call(新this指向, 参数1, 参数2, ... ... , 参数n)(传递的参数按顺序罗列出来)

Fun.apply(新this指向, [参数1, 参数2, ... ... , 参数n])(传递的参数以数组的形式传递,不在意参数顺序)

  • bind()方法会创建一个新函数,称为绑定函数,绑定函数被调用时,会以创建它时传入bind()方法的第一个参数作为this,传入的其他参数则只作为绑定参数的入参。

原型链与原型

每个JS函数都有一个属性prototype,还属性指向一个对象,这个对象被称为原型对象。准确讲,这个对象为函数的实例的原型对象。所有由这个函数构造出来的实例都有一个__proto__指向原型对象.

原型链如下图所示

Promise

Promise解决了JS网络请求循环嵌套调用导致的回调地狱问题,一般使用场景是用于封装网络请求,或是解决循环调用导致的回调地狱问题。Promise在使用过程中一般会搭配async/await使用,用promise封装axios,调用时用async/await拿到和处理请求数据结果。

Promise有3个状态机:pending、resolved(fufilled)、reject。

Promise主要有两个方法:

  • promise.all():所有promise全部执行完之后统一返回结果,若其中有一个promise执行失败则直接报错,不再执行剩余未执行的promise。
  • promise.race():

Promise的简单实现

function Promise(executor) {
  var self = this
  self.statis = "pending"
  self.data = undefined
  self.onResolvedCallback = []
  function resolve(value) {
    if (self.status === "pending") {
      self.status = "resolved"
      self.data = value
      for (var i = 0; i < self.onResolvedCallback.length; i++) {
        self.onResolvedCallback[i] = value
      }
    }
  }
  Promise.peototype.then = function(resolve) {
    this.onResolvedCallback.push(resolve)
  }
}

Promise.all()的简单实现

const customAll = function(iterable) {
  return new Promise((resolve, reject) => {
    let count = 0, results = []
    // 遍历所有对象
    for (const i in iterable) {
      const v = iterable[i]
      if (typeof v === "object" && typeof v.then === "function") {
        v.then((res) => {
          results[i] = res
          if (--count === 0) {
            resolve(results)
          }
        }, reject)
        count++
      } else {
        resuilts[i] = v
      }
    }
  })
}

let p1 = new Promise((resolve) => {
  setTimeout(resolve, 200, 1)
})

let p2 = Promise.reject(2)
let p3 = 3

customAll([p1, p2, p3]).then(
    (res) => {
        console.log(res)
}).catch(err => {
    console.log('报错:', err)
})
// 结果为:    报错:2


customAll([p1, p3]).then(
    (res) => {
        console.log(res)
}).catch(err => {
    console.log('报错:', err)
})

// 结果为:      [ 1, 3 ]

Promise.all()执行失败后,如何返回内部已经执行成功的结果?

参考文章:理解Promise.all,Promise.all与Promise.race的区别,如何让Promise.all在rejected失败后依然返回resolved成功结果