前端面试——ES6及以上

let、var、const,块做用域的实现,ES6和ES5不一样的实现方法。

一、let 和 const 定义的变量不会出现变量提高,而 var 定义的变量会提高。ajax

二、let 和 const 是JS中的块级做用域json

三、let 和 const 不容许重复声明(会抛出错误)数组

四、let 和 const 定义的变量在定义语句以前,若是使用会抛出错误(造成了暂时性死区),而 var 不会。promise

五、const 声明一个只读的常量。一旦声明,常量的值就不能改变(若是声明是一个对象,那么不能改变的是对象的引用地址) 变量提高就是变量在声明以前就可使用,值为undefined。 在代码块内,使用 let/const 命令声明变量以前,该变量都是不可用的(会抛出错误)。这在语法上,称为“暂时性死区”。暂时性死区也意味着 typeof 再也不是一个百分百安全的操做。 暂时性死区的本质就是,只要一进入当前做用域,所要使用的变量就已经存在了,可是不可获取,只有等到声明变量的那一行代码出现,才能够获取和使用该变量。安全

箭头函数与function的区别

箭头函数没有本身的 this, 它的this继承于上一层代码块的this。 箭头函数是普通函数的简写,能够更优雅的定义一个函数,和普通函数相比,有如下几点差别: 一、函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象。 二、不可使用 arguments 对象,该对象在函数体内不存在。若是要用,能够用 rest 参数代替。 三、不可使用 yield 命令,所以箭头函数不能用做 Generator 函数。 四、不可使用 new 命令,由于:没有本身的 this,没法调用 call,apply。bash

迭代器Generator、Iterator

Generators(生成器)
生成器是一个函数,它能够退出函数,稍后从新进入函数。
// generator-example.js
function* generator(){ 
  yield 1; 
  yield 2; 
  yield 3; 
}; 

for (const g of generator()) { 
  console.log(g); 
}

// Output:
// 1
// 2
// 3复制代码

Promise.all()和race()、finally的实现

promise构造函数是同步执行的,then方法是异步执行的
数据结构

all(list) {
        return new Promise((resolve, reject) => {
            let resValues = [];
            let counts = 0;
            for (let [i, p] of list) {
                resolve(p).then(res => {
                    counts++;
                    resValues[i] = res;
                    if (counts === list.length) {
                        resolve(resValues)
                    }
                }, err => {
                    reject(err)
                })
            }
        })
    }
    
Promise._race = promises => new Promise((resolve, reject) => {
        promises.forEach(promise => {
                promise.then(resolve, reject)
        })
})

Promise.prototype.finally = function (callback) {
  let P = this.constructor;
  return this.then(
    value  => P.resolve(callback()).then(() => value),
    reason => P.resolve(callback()).then(() => { throw reason })
  );
};复制代码

setTimeout、Promise、Async/Await 的区别

一、setTimeoutapp

console.log('script start')    //1. 打印 script start
setTimeout(function(){
  console.log('settimeout')   // 4. 打印 settimeout
})      // 2. 调用 setTimeout 函数,并定义其完成后执行的回调函数
console.log('script end')       //3. 打印 script start
// 输出顺序:script start->script end->settimeout复制代码

二、Promise 异步

Promise自己是同步的当即执行函数, 当在executor中执行resolve或者reject的时候, 此时是异步操做, 会先执行then/catch等,当主栈完成后,才会去调用resolve/reject中存放的方法执行,打印p的时候,是打印的返回结果,一个Promise实例。async

console.log('script start')
let promise1 = new Promise(function (resolve) {
  console.log('promise1')
  resolve()
  console.log('promise1 end')
}).then(function () {
  console.log('promise2')
})
setTimeout(function(){
  console.log('settimeout')
})
console.log('script end')
// 输出顺序: script start->promise1->promise1 end->script end->promise2->settimeout复制代码

三、async/await

async function async1(){
 console.log('async1 start');
  await async2();
  console.log('async1 end')
}
async function async2(){
  console.log('async2')
}
console.log('script start');
async1();
console.log('script end')
// 输出顺序:script start->async1 start->async2->script end->async1 end
复制代码

async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操做完成,再执行函数体内后面的语句。能够理解为,是让出了线程,跳出了 async 函数体。 

Proxy

var target = {
   name: 'obj'
 };
 var logHandler = {
   get: function(target, key) {
     console.log(`${key} 被读取`);
     return target[key];
   },
   set: function(target, key, value) {
     console.log(`${key} 被设置为 ${value}`);
     target[key] = value;
   }
 }
 var targetWithLog = new Proxy(target, logHandler);
 targetWithLog.name; // 控制台输出:name 被读取
 targetWithLog.name = 'others'; // 控制台输出:name 被设置为 others
console.log(target.name); // 控制台输出: others复制代码

Set 和 Map

Set 和 Map 主要的应用场景在于 数据重组 和 数据储存 Set 是一种叫作集合的数据结构,Map 是一种叫作字典的数据结构

一、集合(Set) ES6 新增的一种新的数据结构,相似于数组,但成员是惟一且无序的,没有重复的值。 Set 自己是一种构造函数,用来生成 Set 数据结构。

二、字典(Map) 集合 与 字典 的区别:

  • 共同点:集合、字典 能够储存不重复的值

  • 不一样点:集合 是以 [value, value]的形式储存元素,字典 是以 [key, value] 的形式储存

JS 异步解决方案的发展历程以及优缺点

一、回调函数(callback) setTimeout(() => { // callback 函数体 }, 1000) 缺点:回调地狱,不能用 try catch 捕获错误,不能 return;

回调地狱的根本问题在于:

缺少顺序性: 回调地狱致使的调试困难,和大脑的思惟方式不符 嵌套函数存在耦合性,一旦有所改动,就会牵一发而动全身,即(控制反转) 嵌套函数过多的多话,很难处理错误;

ajax('XXX1', () => {
    // callback 函数体
    ajax('XXX2', () => {
        // callback 函数体
        ajax('XXX3', () => {
            // callback 函数体
        })
    })
})复制代码

优势:解决了同步的问题(只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。)

二、Promise 

Promise就是为了解决callback的问题而产生的。

Promise 实现了链式调用,也就是说每次 then 后返回的都是一个全新 Promise,若是咱们在 then 中 return ,return 的结果会被 Promise.resolve() 包装

优势:解决了回调地狱的问题

ajax('XXX1')
  .then(res => {
      // 操做逻辑
      return ajax('XXX2')
  }).then(res => {
      // 操做逻辑
      return ajax('XXX3')
  }).then(res => {
      // 操做逻辑
  })复制代码

缺点:没法取消 Promise ,错误须要经过回调函数来捕获

三、Generator 特色:能够控制函数的执行,能够配合 co 函数库使用

function *fetch() {
    yield ajax('XXX1', () => {})
    yield ajax('XXX2', () => {})
    yield ajax('XXX3', () => {})
}
let it = fetch()
let result1 = it.next()
let result2 = it.next()
let result3 = it.next()复制代码

四、Async/await async、await 是异步的终极解决方案

优势是:代码清晰,不用像 Promise 写一大堆 then 链,处理了回调地狱的问题

缺点:await 将异步代码改形成同步代码,若是多个异步操做没有依赖性而使用 await 会致使性能上的下降。

async function test() {
  // 如下代码没有依赖性的话,彻底可使用 Promise.all 的方式
  // 若是有依赖性的话,其实就是解决回调地狱的例子了
  await fetch('XXX1')
  await fetch('XXX2')
  await fetch('XXX3')
}复制代码

实现一个 sleep 函数,好比 sleep(1000) 意味着等待1000毫秒,可从 Promise、Generator、Async/Await 等角度实现 ?

//Promise
const sleep = time => {
  return new Promise(resolve => setTimeout(resolve,time))
}

sleep(1000).then(()=>{
  console.log(1)
})

//Generator
function* sleepGenerator(time) {
  yield new Promise(function(resolve,reject){
    setTimeout(resolve,time);
  })
}
sleepGenerator(1000).next().value.then(()=>{console.log(1)})


//async
function sleep(time) {
  return new Promise(resolve => setTimeout(resolve,time))
}
async function output() {
  let out = await sleep(1000);
  console.log(1);
  return out;
}
output();

//ES5
function sleep(callback,time) {
  if(typeof callback === 'function')
    setTimeout(callback,time)
}

function output(){
  console.log(1);
}
sleep(output,1000);复制代码

promise封装ajax

var getJSON = url=>{
var promise = new Promise((resolve,reject)=>{
  var client = new   XMLHttpRequest()
  client.open("GET",url);
  client.onreadystatechange = hander;
  client.responseType = "json"
  client.setRequesHeader("Accept","application/json");
  client.send()
  function handler(){
    if(this.readyState!==4){
    return ;
	}
	if(this.status===200){
  	resolve(this.response)
	}else {
  	reject(new Error(this.statusText))
	}
	}
})
return promise;
}

getJSON("/posts.json").then((json)=>{
    console.log(json)
},(error)=>{
  console.log(error)
})复制代码

promise如何取消?

let promise = new Promise(function(resolve, reject){
    resolve('第一次成功')
})

promise.then(function(val) {
    // 两种方法意思都表明报错,【中断下一步,直接报错】
  //第一种方法
    throw new error()
  // 第二种方法
  return Promise.reject()

}).then(function(val) {
    console.log('被跳过的方法')
}).catch(function(val) {
    console.log('返回失败')
})复制代码
相关文章
相关标签/搜索