关于面试:前端面试宝典ES6核心知识篇

29次阅读

共计 9333 个字符,预计需要花费 24 分钟才能阅读完成。

前言:

想零碎学习前端面试题,强烈推荐浏览 在线电子书(反对手机版,不断更新)。

本书特点:零碎全面(涵盖前端核心技术点),简洁,针对性强(针对面试场景设计)。

欢送在 github 上留言反馈

ES6+

[TOC]

介绍下 Generator?

Generator 函数是 ES6 提供的一种 异步编程解决方案,Generator 函数是分段执行的,yield表达式是 暂停执行 的标记,而 next 办法 能够 复原执行

Generator 函数是一个状态机,封装了多个外部状态。执行 Generator 函数会返回一个遍历器对象,能够顺次遍历 Generator 函数外部的每个状态。

Generator 与一般函数的区别:

  • 【不执行】调用 Generator 函数后,该函数并不执行
  • 【返回指针】返回的是一个指向外部状态的指针对象,而不是函数运行后果(遍历器对象 Iterator Object)
  • 【持续运行】必须调用遍历器对象的 next 办法,使得指针移向下一个状态,每次调用 next 办法,就继续执行,直到遇到下一个 yield 表白 式(或 return 语句)为止。

Generator API:

  • next(): 返回一个由 yield 表达式生成的值
  • return(): 返回给定的值并完结生成器
  • throw(): 向生成器抛出一个谬误
function* helloWorldGenerator(){
    yield 'hello';   // 遇到 yield 暂停执行
    yield 'world';
    return 'ending';
}

let hw = helloWorldGenerator();  // 调用不执行函数,只是返回一个遍历器对象
hw.next();  //{value:'hello',done:false}  调用 next 办法继续执行,直到遇到 yield 或 return 表达式
hw.next(); //{value:'world',done:false}
hw.next(); //{value:'ending',done:true}
hw.next(); //{value:undefind,donw:true}  

参考资料:

Generator 函数的语法

ES6 Set 和 Array 的区别?

区别:

  • 【重复性】

    • set: value 不反复 // 通过此个性,可用来去重
    • array: value 可反复

ES6 Map 和 Objects 的区别?

Map 对象保留键值对,工作值(对象或原始值)都能够做为一个键或一个值

区别(Maps 的长处):

  • 【key 值类型】

    • Map:key 能够是对象
    • Objects: key 只能是一个 string 或是 symbol
  • 【键的程序】

    • Map: 有序
    • Objects: 无序
  • 【size】

    • -Map: 减少 size 属性,间接获取
    • Objects: 只能依附手动计算
  • 【键名抵触】

    • Map: 默认不蕴含任何键,只蕴含显式插入的键
    • Object: object 都有本人的原型,原型链上的键名有可能和你本人对象上的设置的键名产生抵触(ES5 开始可用 Object.create(null)来创立一个没原原型的对象,但这种用法不常见)
  • 【性能】

    • Map: 在频繁增删键值对的场景下体现更好
    • Object: 在频繁增加 / 删除键值对的场景下未作出优化

箭头函数的 this 指向哪里?

  • 默认绑定外层 this
  • 不能应用 call 办法批改外面的 this

    • - 起因:函数的 this 能够用 call 办法来手动指定,而为了缩小 this 的复杂性,箭头函数无奈用 call 办法来指定 this

参考资料:

JS 中的箭头函数与 this

箭头函数与一般函数区别?

箭头函数的长处

  • 语法更简洁

    • 不必写 function 更简洁 // let sum=()=>{console.log(11);}
    • 只有一个参数的状况下,不必括号,间接写参数 // let sum = num1= > num1*2
    • 返回体只有一句的状况下,能够省去大括号 // let sum=(num1,num2)=> num1+num2
    • 如果箭头函数的函数体只有一条语句,并且 须要返回值,能够给这条语句前加一个 void // let fn=()=> void donotReturn()
  • 箭头函数不会创立本人的 this(它只会从本人的作用域上一层继承 this)

    • 定义时所处外层如执行环境的上下文,并继承这个 this,之后永远不会批改
var id = 'Global';

function fun1() {
    // setTimeout 中应用一般函数
    setTimeout(function(){console.log(this.id);
    }, 2000);
}

function fun2() {
    // setTimeout 中应用箭头函数
    setTimeout(() => {console.log(this.id);
    }, 2000)
}

fun1.call({id: 'Obj'});     // 'Global'

fun2.call({id: 'Obj'});     // 'Obj'

参考资料:

ES6 – 箭头函数、箭头函数与一般函数的区别

什么是严格模式(use strict)?

特点:

  • 【谨严】对语法要求更标准,打消 js 语法的一些不合理、不谨严之处,缩小一些怪异行为
  • 【平安】打消代码运行的一些不平安之处
  • 【高效】进步编译器效率,减少运行速度
  • 【扩展性】为将来新版本 js 做好铺垫

调用形式:在代码最后面增加一行代码(”use strice”;)

  • 针对整个脚本文件
  • 针对单个函数

扭转:

  • 全局变量显式申明:不能省略 var/const/let 关键词
  • 动态绑定:让属性和办法在编译阶段就确定指向哪个对象

    • 禁止应用 with 语句
    • 创设 eval 作用域
  • 加强字全措施:

    • 禁止 this 指向全局对象
    • 禁止在函数外部遍历调用栈
  • 禁止删除变量(除非 configurable 属性为 true)
  • 显式报错:

    • 只读属性赋值
    • 对禁止扩大的对象增加新属性:
    • 删除一个不可删除的属性:delete object.prototype
  • 重名谬误
  • 对象不能重名的属性(之前是笼罩)
  • 函数不能有重名的参数
  • 禁止八进制表示法
  • arguments 对象的限度:arguments 是函数的参数,对它的应用做了限度

    • 不容许对 arguments 赋值
    • arguments 不再追踪参数的变动
    • 禁止应用 arguments.callee: 无奈在匿名函数外部调用本身
  • 函数必须申明在顶层:不容许在非函数的代码块内申明函数(比方 if,for),只容许在全局作用域或函数作用域的顶层申明函数
  • 保留字:新增了一些保留字,向未来 js 新版本过渡

    • let ,private,public,static ,package,yield,interface,protected,implements

js 语法不标准的几个中央:

  • 【变量定义】能够不应用 var/const/let 关键词,间接定义

参考资料:

Javascript 严格模式详解

介绍下 js 的装璜器(decorators)?

Decorator 就是一种动静地往一个类中增加新的行为的设计模式,它能够在类时,扩大一个类的性能,并且 去批改类自身的属性和办法,使其能够在不同类之间更灵便的共用一些属性和办法;

润饰模式(Decortaor),是面向对象编程畛域中,一种动静地往一个类中增加新的行为的设计模式。润饰模式相比生成子类更加灵便,这样能够给某个对象而不是整个类增加一些性能

用法:

1) 装璜类

@FooDecorator
class Foo {

}

function FooDecorator(target){// target 就是这个 class 的原型对象}

2) 装璜属性

// 给 MyClass 所有实例的  getType 属性设置为仅为可读不可更改的属性 readonly
class MyClass {constructor(){this.type="myClass"}
    @readonly
    getType(){return this.type}
}

function readonly(target, key, discriptor){
    discriptor.writable = false
    return discriptor
}

3)多个装璜器

class MyClass {constructor(){this.type="myClass"}
    @readonly
    @logHello
    getType(){return this.type}
}

// 装璜器让类的 getType 办法不可更改
function readonly(target, key, discriptor){
    discriptor.writable = false
    return discriptor
}

// 让每次调用类中的 getType 办法会在控制台输入 hello
function logHello(target, key, discriptor){const oldFn = target[key]
    target[key] = function(...rest){console.log('Hello')
        return oldFn.call(this,...rest)
    }
    return target
}

参考资料:

JS 装璜器,一篇就够
[学习 ES7 语法 decorator 装璜器]()

创建对象的三种形式?

  • 字面量
  • 构造函数
  • Object.create

参考资料:

[Object.create()、new Object()和 {} 的区别]()

箭头函数?

ES6 罕用 API 有哪些?

let,const:变量,常量
变量的解构赋值:
promise:解决异步
字符串扩大:for..of 字符串遍历接口,repeat 将一个新字符串分量 N 次,模板字符串 $(baseUrl)
数值扩大:math.trunc()去掉小数局部,sign 判断一个数是正 / 负 / 零,指数运算符 **,
函数扩大:箭头函数(不绑定本人的 this)
数组扩大:填充数组 (fill), 复制数据 const a2=[…a1]
对象扩大:
正则的扩大:
减少 async 函数:对异步的解决

AMD 和 CMD 的区别,ES6 模块与 CommonJs 模块有什么区别?

罕用的模块化办法:

模块名 导出模块 引入模块 加载形式 阐明
ES6 export import 动态加载 输入的援用,动态援用,只读属性
commonjs module.exports require 动静援用 输入值的浅拷贝对象,动静加载,可读可写。nodejs 中的规范
AMD(requirejs) define require 异步 依赖前置,提前执行(在模块定义的时候就要引入)
CMD(sea.js) define require([“jquery”,”math”],,()=>{}) 异步 依赖就近,提早执行(用到的时候才引入)

CommonJs(require)与 ES6(import)的区别:

  • require: 输入的是一个值的浅拷贝对象,import 输入的是一个值 的援用(即 es6 module 只存只读,不能扭转其值,具体点就是指针指向不能变,相似 const)
  • require 是动静引入,import 是动态加载了;动静引入的形式,引入的对象能够是一个变量,或者能通过计算出来的地址
  • require 是同步加载模块,import 命令是异步加载,require 有一个独立的模块依赖的解析阶段

参考:https://es6.ruanyifeng.com/#d…

/ AMD 写法 /

define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) {

​     // 等于在最后面申明并初始化了要用到的所有模块

​    a.doSomething();

​    if (false) {

​        // 即使没用到某个模块 b,但 b 还是提前执行了

​        b.doSomething()

​    }

});

/ CMD 写法 /

define(function(require, exports, module) {​    var a = require('./a'); // 在须要时申明

​    a.doSomething();

​    if (false) {​        var b = require('./b');

​        b.doSomething();

​    }

});

js 中 let ,var 区别,let 有什么长处?

相同点:都是定义这是的,都能够批改

let 长处:

  • 不能反复申明:var 能够反复申明
  • 不存在变量晋升:let 不存在变量晋升,未定义的变量会报:未捕捉的援用谬误
  • 暂时性死区:只有块级作用域内存在 let 命令,它所申明的变量变绑定这个区域,不再受内部影响
  • 领有块级作用域:ES5 中只有全局和函数作用域,没有块级作用域,let 会产生块级作用域。
    • var 没有块级作用域的一些问题
        1. 内层变量会笼罩外层变量;
        1. 用来计数的循环变量泄露为全局变量;

es6/ 7 有什么新个性?

箭头函数(不绑定本人的 this),解构赋值,spread 开展,块级作用域(let,const),promise 异步解决方案,set(没有反复的值)/map 数据结构,proxy 拦截器

重要属性:class 类(类继承 extends,constructor,super)

es7: async(async,await)异步操作, 返回 promise 对象,能够接着用.then 办法来连贯;

es6 长期死区?

在 ES6 中,let 和 const 跟 var、class 和 function 一样也会被晋升,只是在进入作用域和被申明之间有一段时间不能拜访它们,这段时间是 长期死区(TDZ)

//console.log(aLet)  // would throw ReferenceError

let aLet;

console.log(aLet); // undefined

aLet = 10;

console.log(aLet); // 10

es6 中的 map 和原生对象有什么区别?

原生对象的 key 只能是 string 类型的,map 的 key 能够是任意值(object,array,function,undefind…)

map 是一种更欠缺的 hash 构造实现;

map 的实用场景,把不同的事件关联起来;、

class 类

class 类的根本介绍?

生成对象的模板

次要组成:

  • constructor:构造方法

    • 默认属性,也可手动增加
    • 间接指向“类”的自身,和 es5 的行为统一 //Person.prototype.constructor === Person
  • 实例办法
  • 静态方法
  • 公有办法、公有属性
  • new.target 属性

特点:

  • 类外部定义的办法,都是不可枚举的(non-enumeerable),和构造函数不一样
//es6 的类,可看作是构造函数的另一种写法
class Person{}
typeof Person  //"function"
Person===Person.prototype.constructor //true

参考资料:

Class 的根本语法

class 与一般构造函数有什么区别?

class 实质应用 prototype 的原型链,只是一种语法糖;

在语法上更加贴合面向对象的语法,在实现继承上更新易读、易了解;

区别:

  • 【变量晋升】

    • 类:没有
    • 构造函数:有
  • 【调用】

    • 类:必须应用 new 调用,否则报错
    • 构造函数:可间接调用
  • 【严格模式】

    • 类:类和模块的外部,默认是严格模式,无需应用 use strict 关键词
    • 构造函数:无强制要求
// 类不存在变量晋升
new Person{}; //ReferenceError
class Person{}

在构造函数中调用 super(props)的目标是什么?

es6 语法 中,super 指代父类的构造函数;

react 外面就是指代 React.Component 的构造函数

在调用 super() 之前,无奈在构造函数中应用 this;在 es2015 中,子类必须在 constructor 中调用 super(), 传递 props 给 super() 的起因是便于能在 constructor 拜访 this.props;

参考资料:

React 构造函数中为什么要写 super(props)

Async/Await

对 async await 的了解,外部原理?

实质:async 是 Generator 的语法糖;

async 扭转有如下几个办法

  • 更好的语义化:async 相当于 *,await 相当于 yield;
  • 返回值是 promise,generator 返回的是 Iterator 对象,更不便的应用 then 来操作
  • 内置执行器:async 自带执行器,Generator 须要依附执行器(每次都是执行 g.next()办法);
  • 更广的适用性:async 函数的 await 后盾能够是 promise 对象,也能够是原始类型的值;

async/await 相比 promise 的劣势?

  • 同步写法优雅:使解脱了 then 的链式调用带来的浏览累赘
  • 获取返回值不便:promise 传递两头传十分麻烦,而 async/await 简直是同步的写法,更优雅
  • 错误处理敌对:async/await 可应用成熟的 try/catch,promise 的谬误捕捉十分冗余
  • 调试敌对 :promise 中的 then 应用调试器的步进(step-over) 性能,调试器并不会进入后续的 then 代码块,因为调试器只能跟踪同步代码的【每一步】

promise

介绍下 promise?

Promise 是 es6 引入的一个新的对象,用来解决 js 中异步回调天堂的写法,并不是什么突破性的 api,只是封装了异步回调函数;

使得异步写的更加优雅,可读性更高,而且反对链式操作;

promise 有几个状态?

Promise 一共有三种状态

1. 初始化,状态:pending

2. 当调用 resolve(胜利),状态:pengding=>fulfilled

3. 当调用 reject(失败),状态:pending=>rejected

promise 外部实现原理?

Promise/A+ 标准

  1. pending: 示意初始状态,能够转移到 fullfilled 或者 rejected 状态
  2. fulfilled: 示意操作胜利,不可转移状态
  3. rejected: 示意操作失败,不可转移状态
  4. 必须有一个 then 异步执行办法,then 承受两个参数且必须返回一个 promise

实现思路

咱们定义 Promise1 对象,在对象外部创立 status、reason、fullfilledCallbacks、rejectedCallbacks 这四个属性,这些属性别离示意的意义为:

  1. reason: 保留以后 promise 实例状态
  2. value: 保留 fullfilled 之后的值
  3. reason: 保留 rejected 后的起因
  4. fullfilledCallbacks: fullfilled 回调队列
  5. rejectedCallbacks:rejected 回调队列

咱们定义 resolve 和 reject 办法用于解决传进来的 executor 函数。在以后实例调用 then 办法时候去返回新的 Promise1 实例,并判断以后实例状态是否 pendding,如果 pendding,将传入的胜利和失败回调函数退出队列,在内部调用 resolve 或者 reject 时候,再次判断以后状态是否 pendding,如果是,则批改以后实例状态为 fullfilled 或者 rejected,并批量执行回调队列中的回调函数。

promise 状态流转过程

参考资料:

今日头条: 介绍下 Promise,外部实现(一面)

图解 Promise 实现原理(一)—— 根底实现

promise 和 async 解决失败有什么区别?

## promise

function asyncTast(url){return new Promise(resolve,reject) => {}}


## async

try{}catch(e){console.log(e);

}

如何设计 promise.all?

总结 promise.all 的特点

1、接管一个 Promise 实例的数组或具备 Iterator 接口的对象,

2、如果元素不是 Promise 对象,则应用 Promise.resolve 转成 Promise 对象

3、如果全副胜利,状态变为 resolved,返回值将组成一个数组传给回调

4、只有有一个失败,状态就变为 rejected,返回值将间接传递给回调
all() 的返回值也是新的 Promise 对象

实现思路:

function promiseAll(promises) {return new Promise(function(resolve, reject) {if (!isArray(promises)) {return reject(new TypeError('arguments must be an array'));
    }
    var resolvedCounter = 0;
    var promiseNum = promises.length;
    var resolvedValues = new Array(promiseNum);
    for (var i = 0; i < promiseNum; i++) {(function(i) {Promise.resolve(promises[i]).then(function(value) {
          resolvedCounter++
          resolvedValues[i] = value
          if (resolvedCounter == promiseNum) {return resolve(resolvedValues)
          }
        }, function(reason) {return reject(reason)
        })
      })(i)
    }
  })
}

Promise 构造函数是同步执行还是异步执行,那么 then 办法呢?

promise 构造函数是同步执行的,then 办法是异步执行的

const promise = new Promise((resolve, reject) => {console.log(1)
  resolve()
  console.log(2)
})

promise.then(() => {console.log(3)
})

console.log(4)

参考资料:

Promise 构造函数是同步执行还是异步执行,那么 then 办法呢?

API

Map api?

Map 保留键值对,并且可能记住键的原始插入程序。任何值 都能够作为一个 或一个

  • Map 的属性

    • size
  • Map 的办法
    • 增:set({key:value}) // 减少对象
    • 删:

      • -clear() // 清空对象
      • delete(key) // 删除对象
    • 改:
    • 查:

      • -get(key) // 获取对象
      • has(key) // 返回一个布尔值,判断 Map 实例是否蕴含键对应的值
    • 遍历:

      • forEach(callbackFn[,thisArg]) // 删除对象
    • 其余:

      • keys() // 返回类型:Iterator 对象,获取 keys 列表
      • values() // 返回类型:Iterator 对象 , 返回一个新的 Iteratror 对象,它按插入程序蕴含了 Map 对象中每个元素的值

Set api?

set 对象容许你存储 任何类型 惟一值,无论是原始值或者是对象援用

属性:

  • 长度:size

实例办法:(Set.prototype)

  • 创立:new Set(); new Set([1,2]);
  • 增(只反对增加在尾部):

    • 尾:只承受一个参数,但可链式调用,mySet.add(1).add(2)
  • 删:

    • 指定 item : delete(value) //Array(value=item),Object (value=object)
    • 清空:clear()
  • 查:

    • 判断值是否存在:has(value) //Array(value=item),Object (value=object)
  • 遍历:

    • for 循环:for(const item of set1){console.log(item);}
    • forEach: 无返回值

正文完
 0