一面 1:ES 基础知识点与高频考题解析

一面 1:ES 基础知识点与高频考题解析

JavaScript 是 ECMAScript 规范的一种实现,本小节重点梳理下 ECMAScript 中的常考知识点,而后就一些容易出现的题目进行解析。前端

知识点梳理

  • 变量类型程序员

    • JS 的数据类型分类和判断
    • 值类型和引用类型
  • 原型与原型链(继承)es6

    • 原型和原型链定义
    • 继承写法
  • 做用域和闭包面试

    • 执行上下文
    • this
    • 闭包是什么
  • 异步json

    • 同步 vs 异步
    • 异步和单线程
    • 前端异步的场景
  • ES6/7 新标准的考查数组

    • 箭头函数
    • Module
    • Class
    • Set 和 Map
    • Promise
    • *

变量类型

JavaScript 是一种弱类型脚本语言,所谓弱类型指的是定义变量时,不须要什么类型,在程序运行过程当中会自动判断类型。浏览器

ECMAScript 中定义了 6 种原始类型:网络

  • Boolean
  • String
  • Number
  • Null
  • Undefined
  • Symbol(ES6 新定义)

注意:原始类型不包含 Object。数据结构

题目:类型判断用到哪些方法?

typeof

typeof xxx获得的值有如下几种类型:undefined boolean number string object functionsymbol ,比较简单,再也不一一演示了。这里须要注意的有三点:闭包

  • typeof null结果是object ,实际这是typeof的一个bug,null是原始值,非引用类型
  • typeof [1, 2]结果是object,结果中没有array这一项,引用类型除了function其余的所有都是object
  • typeof Symbol()typeof获取symbol类型的值获得的是symbol,这是 ES6 新增的知识点

instanceof

用于实例和构造函数的对应。例如判断一个变量是不是数组,使用typeof没法判断,但可使用[1, 2] instanceof Array来判断。由于,[1, 2]是数组,它的构造函数就是Array。同理:

function Foo(name) {
    this.name = name
}
var foo = new Foo('bar')
console.log(foo instanceof Foo) // true
题目:值类型和引用类型的区别

值类型 vs 引用类型

除了原始类型,ES 还有引用类型,上文提到的typeof识别出来的类型中,只有objectfunction是引用类型,其余都是值类型。

根据 JavaScript 中的变量类型传递方式,又分为值类型引用类型,值类型变量包括 Boolean、String、Number、Undefined、Null,引用类型包括了 Object 类的全部,如 Date、Array、Function 等。在参数传递方式上,值类型是按值传递,引用类型是按共享传递。

下面经过一个小题目,来看下二者的主要区别,以及实际开发中须要注意的地方。

// 值类型
var a = 10
var b = a
b = 20
console.log(a)  // 10
console.log(b)  // 20

上述代码中,a b都是值类型,二者分别修改赋值,相互之间没有任何影响。再看引用类型的例子:

// 引用类型
var a = {x: 10, y: 20}
var b = a
b.x = 100
b.y = 200
console.log(a)  // {x: 100, y: 200}
console.log(b)  // {x: 100, y: 200}

上述代码中,a b都是引用类型。在执行了b = a以后,修改b的属性值,a的也跟着变化。由于ab都是引用类型,指向了同一个内存地址,即二者引用的是同一个值,所以b修改属性时,a的值随之改动。

再借助题目进一步讲解一下。

说出下面代码的执行结果,并分析其缘由。
function foo(a){
    a = a * 10;
}
function bar(b){
    b.value = 'new';
}
var a = 1;
var b = {value: 'old'};
foo(a);
bar(b);
console.log(a); // 1
console.log(b); // value: new

经过代码执行,会发现:

  • a的值没有发生改变
  • b的值发生了改变

这就是由于Number类型的a是按值传递的,而Object类型的b是按共享传递的。

JS 中这种设计的缘由是:按值传递的类型,复制一份存入栈内存,这类类型通常不占用太多内存,并且按值传递保证了其访问速度。按共享传递的类型,是复制其引用,而不是整个复制其值(C 语言中的指针),保证过大的对象等不会由于不停复制内容而形成内存的浪费。

引用类型常常会在代码中按照下面的写法使用,或者说容易不知不觉中形成错误

var obj = {
    a: 1,
    b: [1,2,3]
}
var a = obj.a
var b = obj.b
a = 2
b.push(4)
console.log(obj, a, b)

虽然obj自己是个引用类型的变量(对象),可是内部的ab一个是值类型一个是引用类型,a的赋值不会改变obj.a,可是b的操做却会反映到obj对象上。

    • *

原型和原型链

JavaScript 是基于原型的语言,原型理解起来很是简单,但却特别重要,下面仍是经过题目来理解下JavaScript 的原型概念。

题目:如何理解 JavaScript 的原型

对于这个问题,能够从下面这几个要点来理解和回答,下面几条必须记住而且理解

  • 全部的引用类型(数组、对象、函数),都具备对象特性,便可自由扩展属性(null除外)
  • 全部的引用类型(数组、对象、函数),都有一个__proto__属性,属性值是一个普通的对象
  • 全部的函数,都有一个prototype属性,属性值也是一个普通的对象
  • 全部的引用类型(数组、对象、函数),__proto__属性值指向它的构造函数的prototype属性值

经过代码解释一下,你们可自行运行如下代码,看结果。

// 要点一:自由扩展属性
var obj = {}; obj.a = 100;
var arr = []; arr.a = 100;
function fn () {}
fn.a = 100;

// 要点二:__proto__
console.log(obj.__proto__);
console.log(arr.__proto__);
console.log(fn.__proto__);

// 要点三:函数有 prototype
console.log(fn.prototype)

// 要点四:引用类型的 __proto__ 属性值指向它的构造函数的 prototype 属性值
console.log(obj.__proto__ === Object.prototype)

原型

先写一个简单的代码示例。

// 构造函数
function Foo(name, age) {
    this.name = name
}
Foo.prototype.alertName = function () {
    alert(this.name)
}
// 建立示例
var f = new Foo('zhangsan')
f.printName = function () {
    console.log(this.name)
}
// 测试
f.printName()
f.alertName()

执行printName时很好理解,可是执行alertName时发生了什么?这里再记住一个重点 当试图获得一个对象的某个属性时,若是这个对象自己没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找,所以f.alertName就会找到Foo.prototype.alertName

那么如何判断这个属性是否是对象自己的属性呢?使用hasOwnProperty,经常使用的地方是遍历一个对象的时候。

var item
for (item in f) {
    // 高级浏览器已经在 for in 中屏蔽了来自原型的属性,可是这里建议你们仍是加上这个判断,保证程序的健壮性
    if (f.hasOwnProperty(item)) {
        console.log(item)
    }
}
题目:如何理解 JS 的原型链

原型链

仍是接着上面的示例,若是执行f.toString()时,又发生了什么?

// 省略 N 行

// 测试
f.printName()
f.alertName()
f.toString()

由于f自己没有toString(),而且f.__proto__(即Foo.prototype)中也没有toString。这个问题仍是得拿出刚才那句话——当试图获得一个对象的某个属性时,若是这个对象自己没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找

若是在f.__proto__中没有找到toString,那么就继续去f.__proto__.__proto__中寻找,由于f.__proto__就是一个普通的对象而已嘛!

  • f.__proto__Foo.prototype,没有找到toString,继续往上找
  • f.__proto__.__proto__Foo.prototype.__proto__Foo.prototype就是一个普通的对象,所以Foo.prototype.__proto__就是Object.prototype,在这里能够找到toString
  • 所以f.toString最终对应到了Object.prototype.toString

这样一直往上找,你会发现是一个链式的结构,因此叫作“原型链”。若是一直找到最上层都没有找到,那么就宣告失败,返回undefined。最上层是什么 —— Object.prototype.__proto__ === null

原型链中的this

全部从原型或更高级原型中获得、执行的方法,其中的this在执行时,就指向了当前这个触发事件执行的对象。所以printNamealertName中的this都是f

    • *

做用域和闭包

做用域和闭包是前端面试中,最可能考查的知识点。例以下面的题目:

题目:如今有个 HTML 片断,要求编写代码,点击编号为几的连接就 alert弹出其编号
<ul>
    <li>编号1,点击我请弹出1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>

通常不知道这个题目用闭包的话,会写出下面的代码:

var list = document.getElementsByTagName('li');
for (var i = 0; i < list.length; i++) {
    list[i].addEventListener('click', function(){
        alert(i + 1)
    }, true)
}

实际上执行才会发现始终弹出的是6,这时候就应该经过闭包来解决:

var list = document.getElementsByTagName('li');
for (var i = 0; i < list.length; i++) {
    list[i].addEventListener('click', function(i){
        return function(){
            alert(i + 1)
        }
    }(i), true)
}

要理解闭包,就须要咱们从「执行上下文」开始讲起。

执行上下文

先讲一个关于 变量提高 的知识点,面试中可能会碰见下面的问题,不少候选人都回答错误:

题目:说出下面执行的结果(这里笔者直接注释输出了)
console.log(a)  // undefined
var a = 100

fn('zhangsan')  // 'zhangsan' 20
function fn(name) {
    age = 20
    console.log(name, age)
    var age
}

console.log(b); // 这里报错
// Uncaught ReferenceError: b is not defined
b = 100;

在一段 JS 脚本(即一个<script>标签中)执行以前,要先解析代码(因此说 JS 是解释执行的脚本语言),解析的时候会先建立一个 全局执行上下文 环境,先把代码中即将执行的(内部函数的不算,由于你不知道函数什么时候执行)变量、函数声明都拿出来。变量先暂时赋值为undefined,函数则先声明好可以使用。这一步作完了,而后再开始正式执行程序。再次强调,这是在代码执行以前才开始的工做。

咱们来看下上面的面试小题目,为何aundefined,而b却报错了,实际 JS 在代码执行以前,要「全文解析」,发现var a,知道有个a的变量,存入了执行上下文,而b没有找到var关键字,这时候没有在执行上下文提早「占位」,因此代码执行的时候,提早报到的a是有记录的,只不过值暂时尚未赋值,即为undefined,而b在执行上下文没有找到,天然会报错(没有找到b的引用)。

另外,一个函数在执行以前,也会建立一个 函数执行上下文 环境,跟 全局上下文 差很少,不过 函数执行上下文 中会多出this arguments和函数的参数。参数和arguments好理解,这里的this我们须要专门讲解。

总结一下:

  • 范围:一段<script>、js 文件或者一个函数
  • 全局上下文:变量定义,函数声明
  • 函数上下文:变量定义,函数声明,thisarguments

this

先搞明白一个很重要的概念 —— this的值是在执行的时候才能确认,定义的时候不能确认! 为何呢 —— 由于this是执行上下文环境的一部分,而执行上下文须要在代码执行以前肯定,而不是定义的时候。看以下例子

var a = {
    name: 'A',
    fn: function () {
        console.log(this.name)
    }
}
a.fn()  // this === a
a.fn.call({name: 'B'})  // this === {name: 'B'}
var fn1 = a.fn
fn1()  // this === window

this执行会有不一样,主要集中在这几个场景中

  • 做为构造函数执行,构造函数中
  • 做为对象属性执行,上述代码中a.fn()
  • 做为普通函数执行,上述代码中fn1()
  • 用于call apply bind,上述代码中a.fn.call({name: 'B'})

下面再来说解下什么是做用域和做用域链,做用域链和做用域也是常考的题目。

题目:如何理解 JS 的做用域和做用域链

做用域

ES6 以前 JS 没有块级做用域。例如

if (true) {
    var name = 'zhangsan'
}
console.log(name)

从上面的例子能够体会到做用域的概念,做用域就是一个独立的地盘,让变量不会外泄、暴露出去。上面的name就被暴露出去了,所以,JS 没有块级做用域,只有全局做用域和函数做用域

var a = 100
function fn() {
    var a = 200
    console.log('fn', a)
}
console.log('global', a)
fn()

全局做用域就是最外层的做用域,若是咱们写了不少行 JS 代码,变量定义都没有用函数包括,那么它们就所有都在全局做用域中。这样的坏处就是很容易撞车、冲突。

// 张三写的代码中
var data = {a: 100}

// 李四写的代码中
var data = {x: true}

这就是为什么 jQuery、Zepto 等库的源码,全部的代码都会放在(function(){....})()中。由于放在里面的全部变量,都不会被外泄和暴露,不会污染到外面,不会对其余的库或者 JS 脚本形成影响。这是函数做用域的一个体现。

附:ES6 中开始加入了块级做用域,使用let定义变量便可,以下:

if (true) {
    let name = 'zhangsan'
}
console.log(name)  // 报错,由于let定义的name是在if这个块级做用域

做用域链

首先认识一下什么叫作 自由变量 。以下代码中,console.log(a)要获得a变量,可是在当前的做用域中没有定义a(可对比一下b)。当前做用域没有定义的变量,这成为 自由变量 。自由变量如何获得 —— 向父级做用域寻找。

var a = 100
function fn() {
    var b = 200
    console.log(a)
    console.log(b)
}
fn()

若是父级也没呢?再一层一层向上寻找,直到找到全局做用域仍是没找到,就宣布放弃。这种一层一层的关系,就是 做用域链

var a = 100
function F1() {
    var b = 200
    function F2() {
        var c = 300
        console.log(a) // 自由变量,顺做用域链向父做用域找
        console.log(b) // 自由变量,顺做用域链向父做用域找
        console.log(c) // 本做用域的变量
    }
    F2()
}
F1()

闭包

讲完这些内容,咱们再来看一个例子,经过例子来理解闭包。

function F1() {
    var a = 100
    return function () {
        console.log(a)
    }
}
var f1 = F1()
var a = 200
f1()

自由变量将从做用域链中去寻找,可是 依据的是函数定义时的做用域链,而不是函数执行时,以上这个例子就是闭包。闭包主要有两个应用场景:

  • 函数做为返回值,上面的例子就是
  • 函数做为参数传递,看如下例子
function F1() {
    var a = 100
    return function () {
        console.log(a)
    }
}
function F2(f1) {
    var a = 200
    console.log(f1())
}
var f1 = F1()
F2(f1)

至此,对应着「做用域和闭包」这部分一开始的点击弹出alert的代码再看闭包,就很好理解了。

    • *

异步

异步和同步也是面试中常考的内容,下面笔者来说解下同步和异步的区别。

同步 vs 异步

先看下面的 demo,根据程序阅读起来表达的意思,应该是先打印100,1秒钟以后打印200,最后打印300。可是实际运行根本不是那么回事。

console.log(100)
setTimeout(function () {
    console.log(200)
}, 1000)
console.log(300)

再对比如下程序。先打印100,再弹出200(等待用户确认),最后打印300。这个运行效果就符合预期要求。

console.log(100)
alert(200)  // 1秒钟以后点击确认
console.log(300)

这俩到底有何区别?—— 第一个示例中间的步骤根本没有阻塞接下来程序的运行,而第二个示例却阻塞了后面程序的运行。前面这种表现就叫作 异步(后面这个叫作 同步 ),即不会阻塞后面程序的运行

异步和单线程

JS 须要异步的根本缘由是 JS 是单线程运行的,即在同一时间只能作一件事,不能“一心二用”。

一个 Ajax 请求因为网络比较慢,请求须要 5 秒钟。若是是同步,这 5 秒钟页面就卡死在这里啥也干不了了。异步的话,就好不少了,5 秒等待就等待了,其余事情不耽误作,至于那 5 秒钟等待是网速太慢,不是由于 JS 的缘由。

讲到单线程,咱们再来看个真题:

题目:讲解下面代码的执行过程和结果
var a = true;
setTimeout(function(){
    a = false;
}, 100)
while(a){
    console.log('while执行了')
}

这是一个颇有迷惑性的题目,很多候选人认为100ms以后,因为a变成了false,因此while就停止了,实际不是这样,由于JS是单线程的,因此进入while循环以后,没有「时间」(线程)去跑定时器了,因此这个代码跑起来是个死循环!

前端异步的场景

  • 定时 setTimeout setInterval
  • 网络请求,如 Ajax <img>加载

Ajax 代码示例

console.log('start')
$.get('./data1.json', function (data1) {
    console.log(data1)
})
console.log('end')

img 代码示例(经常使用于打点统计)

console.log('start')
var img = document.createElement('img')
// 或者 img = new Image()
img.onload = function () {
    console.log('loaded')
    img.onload = null
}
img.src = '/xxx.png'
console.log('end')
    • *

ES6/7 新标准的考查

题目:ES6 箭头函数中的 this和普通函数中的有什么不一样

箭头函数

箭头函数是 ES6 中新的函数定义形式,function name(arg1, arg2) {...}可使用(arg1, arg2) => {...}来定义。示例以下:

// JS 普通函数
var arr = [1, 2, 3]
arr.map(function (item) {
    console.log(index)
    return item + 1
})

// ES6 箭头函数
const arr = [1, 2, 3]
arr.map((item, index) => {
    console.log(index)
    return item + 1
})

箭头函数存在的意义,第一写起来更加简洁,第二能够解决 ES6 以前函数执行中this是全局变量的问题,看以下代码

function fn() {
    console.log('real', this)  // {a: 100} ,该做用域下的 this 的真实的值
    var arr = [1, 2, 3]
    // 普通 JS
    arr.map(function (item) {
        console.log('js', this)  // window 。普通函数,这里打印出来的是全局变量,使人费解
        return item + 1
    })
    // 箭头函数
    arr.map(item => {
        console.log('es6', this)  // {a: 100} 。箭头函数,这里打印的就是父做用域的 this
        return item + 1
    })
}
fn.call({a: 100})
题目:ES6 模块化如何使用?

Module

ES6 中模块化语法更加简洁,直接看示例。

若是只是输出一个惟一的对象,使用export default便可,代码以下

// 建立 util1.js 文件,内容如
export default {
    a: 100
}

// 建立 index.js 文件,内容如
import obj from './util1.js'
console.log(obj)

若是想要输出许多个对象,就不能用default了,且import时候要加{...},代码以下

// 建立 util2.js 文件,内容如
export function fn1() {
    alert('fn1')
}
export function fn2() {
    alert('fn2')
}

// 建立 index.js 文件,内容如
import { fn1, fn2 } from './util2.js'
fn1()
fn2()
题目:ES6 class 和普通构造函数的区别

class

class 其实一直是 JS 的关键字(保留字),可是一直没有正式使用,直到 ES6 。 ES6 的 class 就是取代以前构造函数初始化对象的形式,从语法上更加符合面向对象的写法。例如:

JS 构造函数的写法

function MathHandle(x, y) {
  this.x = x;
  this.y = y;
}

MathHandle.prototype.add = function () {
  return this.x + this.y;
};

var m = new MathHandle(1, 2);
console.log(m.add())

用 ES6 class 的写法

class MathHandle {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  add() {
    return this.x + this.y;
  }
}
const m = new MathHandle(1, 2);
console.log(m.add())

注意如下几点,全都是关于 class 语法的:

  • class 是一种新的语法形式,是class Name {...}这种形式,和函数的写法彻底不同
  • 二者对比,构造函数函数体的内容要放在 class 中的constructor函数中,constructor即构造器,初始化实例时默认执行
  • class 中函数的写法是add() {...}这种形式,并无function关键字

使用 class 来实现继承就更加简单了,至少比构造函数实现继承简单不少。看下面例子

JS 构造函数实现继承

// 动物
function Animal() {
    this.eat = function () {
        console.log('animal eat')
    }
}
// 狗
function Dog() {
    this.bark = function () {
        console.log('dog bark')
    }
}
Dog.prototype = new Animal()
// 哈士奇
var hashiqi = new Dog()

ES6 class 实现继承

class Animal {
    constructor(name) {
        this.name = name
    }
    eat() {
        console.log(`${this.name} eat`)
    }
}

class Dog extends Animal {
    constructor(name) {
        super(name)
        this.name = name
    }
    say() {
        console.log(`${this.name} say`)
    }
}
const dog = new Dog('哈士奇')
dog.say()
dog.eat()

注意如下两点:

  • 使用extends便可实现继承,更加符合经典面向对象语言的写法,如 Java
  • 子类的constructor必定要执行super(),以调用父类的constructor
题目:ES6 中新增的数据类型有哪些?

Set 和 Map

Set 和 Map 都是 ES6 中新增的数据结构,是对当前 JS 数组和对象这两种重要数据结构的扩展。因为是新增的数据结构,目前还没有被大规模使用,可是做为前端程序员,提早了解是必须作到的。先总结一下二者最关键的地方:

  • Set 相似于数组,但数组能够容许元素重复,Set 不容许元素重复
  • Map 相似于对象,但普通对象的 key 必须是字符串或者数字,而 Map 的 key 能够是任何数据类型

Set

Set 实例不容许元素有重复,能够经过如下示例证实。能够经过一个数组初始化一个 Set 实例,或者经过add添加元素,元素不能重复,重复的会被忽略。

// 例1
const set = new Set([1, 2, 3, 4, 4]);
console.log(set) // Set(4) {1, 2, 3, 4}

// 例2
const set = new Set();
[2, 3, 5, 4, 5, 8, 8].forEach(item => set.add(item));
for (let item of set) {
  console.log(item);
}
// 2 3 5 4 8

Set 实例的属性和方法有

  • size:获取元素数量。
  • add(value):添加元素,返回 Set 实例自己。
  • delete(value):删除元素,返回一个布尔值,表示删除是否成功。
  • has(value):返回一个布尔值,表示该值是不是 Set 实例的元素。
  • clear():清除全部元素,没有返回值。
const s = new Set();
s.add(1).add(2).add(2); // 添加元素

s.size // 2

s.has(1) // true
s.has(2) // true
s.has(3) // false

s.delete(2);
s.has(2) // false

s.clear();
console.log(s);  // Set(0) {}

Set 实例的遍历,可以使用以下方法

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。不过因为 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),因此keys()values()返回结果一致。
  • entries():返回键值对的遍历器。
  • forEach():使用回调函数遍历每一个成员。
let set = new Set(['aaa', 'bbb', 'ccc']);

for (let item of set.keys()) {
  console.log(item);
}
// aaa
// bbb
// ccc

for (let item of set.values()) {
  console.log(item);
}
// aaa
// bbb
// ccc

for (let item of set.entries()) {
  console.log(item);
}
// ["aaa", "aaa"]
// ["bbb", "bbb"]
// ["ccc", "ccc"]

set.forEach((value, key) => console.log(key + ' : ' + value))
// aaa : aaa
// bbb : bbb
// ccc : ccc

Map

Map 的用法和普通对象基本一致,先看一下它能用非字符串或者数字做为 key 的特性。

const map = new Map();
const obj = {p: 'Hello World'};

map.set(obj, 'OK')
map.get(obj) // "OK"

map.has(obj) // true
map.delete(obj) // true
map.has(obj) // false

须要使用new Map()初始化一个实例,下面代码中set get has delete顾名便可思义(下文也会演示)。其中,map.set(obj, 'OK')就是用对象做为的 key (不光能够是对象,任何数据类型均可以),而且后面经过map.get(obj)正确获取了。

Map 实例的属性和方法以下:

  • size:获取成员的数量
  • set:设置成员 key 和 value
  • get:获取成员属性值
  • has:判断成员是否存在
  • delete:删除成员
  • clear:清空全部
const map = new Map();
map.set('aaa', 100);
map.set('bbb', 200);

map.size // 2

map.get('aaa') // 100

map.has('aaa') // true

map.delete('aaa')
map.has('aaa') // false

map.clear()

Map 实例的遍历方法有:

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回全部成员的遍历器。
  • forEach():遍历 Map 的全部成员。
const map = new Map();
map.set('aaa', 100);
map.set('bbb', 200);

for (let key of map.keys()) {
  console.log(key);
}
// "aaa"
// "bbb"

for (let value of map.values()) {
  console.log(value);
}
// 100
// 200

for (let item of map.entries()) {
  console.log(item[0], item[1]);
}
// aaa 100
// bbb 200

// 或者
for (let [key, value] of map.entries()) {
  console.log(key, value);
}
// aaa 100
// bbb 200

Promise

Promise是 CommonJS 提出来的这一种规范,有多个版本,在 ES6 当中已经归入规范,原生支持 Promise 对象,非 ES6 环境能够用相似 Bluebird、Q 这类库来支持。

Promise 能够将回调变成链式调用写法,流程更加清晰,代码更加优雅。

简单概括下 Promise:三个状态、两个过程、一个方法,快速记忆方法:3-2-1

三个状态:pendingfulfilledrejected

两个过程:

  • pending→fulfilled(resolve)
  • pending→rejected(reject)

一个方法:then

固然还有其余概念,如catchPromise.all/race,这里就不展开了。

关于 ES6/7 的考查内容还有不少,本小节就不逐一介绍了,若是想继续深刻学习,能够在线看《ES6入门》。

小结

本小节主要总结了 ES 基础语法中面试常常考查的知识点,包括以前就考查较多的原型、异步、做用域,以及 ES6 的一些新内容,这些知识点但愿你们都要掌握。

相关文章
相关标签/搜索