前端面試——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('返回失敗')
})複製代碼
相關文章
相關標籤/搜索