01 | 能讓我想一想嗎?。。。對不起,我忘記了!

前言

最近本身面試和觀看同窗面試後,感慨萬分!其實不少知識點真的看過,可是在面試過程當中會忽然想不起來,你說可氣不可氣。這個有個好方法--提詞器,這個須要你用本身的語言去整理簡短的提詞器,而後經過提詞器的內容去拓展這個問題的知識點。在整理的過程當中,讓本身再次去理解加深本身的印象,也有利於本身在面試過程當中的表達。表達在面試過程當中很是重要,若是你知道這個問題的答案,就由於你沒表達清楚,讓面試官感受你仍是沒弄懂的狀態,致使這道題失分,這是否是很惋惜呢?其實還能夠經過和同窗或者朋友對練的形式,讓本身的表達能力獲得提高。node

image.png

面試題高頻考點

var、let和const的區別

  • 做用域不一樣(是否含有塊級元素)
    • 塊級做用域:聲明的變量只在該代碼塊做用域內有效
    • var沒有塊級做用域,let、const有塊級做用域
  • 是否存在暫時性死區
    • let和const定義的變量是存在暫時性死區的,而var沒有,原理以下:
    • 對於var而言,當進入var變量的做用域時,會當即爲它建立存儲空間,並對它進行初始化,賦值爲undefined,當函數加載到變量聲明語句時,會根據語句對變量賦值。
    • 而let和const卻不同,當進入let變量的做用域時,會當即給它建立存儲空間,可是不會對它進行初始化
  • 是否存在變量提高
    • 變量提高:變量在聲明以前可使用面試

    • var聲明的變量存在變量提高,let、const不存在變量提高數組

  • 可否重複聲明
    • var聲明的能夠重複聲明, let 和const聲明的不能夠重複聲明
  • 變量可否被修改
    • var、let聲明的變量能夠被修改,const聲明的常量不可修改

面試官深挖的問題

QQ圖片20210514095847.gif

1.那麼var是什麼做用域呢?這個我在面試的時候就被問到過,那麼你知道嗎?

var的做用域是在被定義的時候決定的,以下:
- 在函數內部定義的話,那麼var就是局部變量,其做用域稱爲函數做用域/局部做用域
- 在函數外部定義的話,那麼var就是全局變量,其做用域稱爲全局做用域
複製代碼

2.變量提高和函數提高的相關問題

//1
var a = 1;
function b(){
  var a = 2;
  console.log(a)   //輸出的是什麼 爲何
}
b()

//2
var a = 1; 
function a(){
	
}
console.log(a)  //輸出的是什麼 爲何
//3
var a = 1;
function a(){
	console.log(a);
}
a()//輸出的是什麼 爲何
複製代碼
  • 首先第一個輸出的是2,這個涉及的就是做用域問題,由於在b()內部定義變量a,全部先訪問函數內部的變量a,全部輸出的是2,若是函數內部沒有定義變量a,那麼就訪問全局中定義的a,輸出的機會是1promise

  • 第二個輸出的是1,這裏隱藏了變量提高和函數提高的優先級,函數聲明提高>變量聲明提高.當js解析器在遇到函數聲明時,會優先將其提高到定義體頂部,其次再是var聲明的變量,這樣就致使函數a被變量a給覆蓋的狀況,因此最終將打印1瀏覽器

  • 第三個輸出的是TypeError: a is not a function,這個和第二個相似,函數a被變量a給覆蓋,因此當調用a()的時候,就會報錯由於a只是一個變量了。微信

//3
var a = 1;
function a(){
	console.log(a);
}
// a()
console.log(a); // 輸出的是 1
複製代碼

3.const聲明的常量不能夠改變=>const聲明的對象屬性是否能夠改變?

const obj = {
    name:"大海",
    age: 18
}
obj.age = 20;
console.log(`name:${obj.name},age:${obj.age}`); 
//輸出 name:大海,age:20
複製代碼

由於對象是引用類型的,obj中保存的僅是對象的指針,這就意味着,const僅保證指針不發生改變,修改對象的屬性不會改變對象的指針,因此是被容許的。也就是說const定義的引用類型只要指針不發生改變,其餘的不論如何改變都是容許的。markdown

const obj = {
    name:"大海",
    age: 18
}
// obj.age = 20;
// console.log(`name:${obj.name},age:${obj.age}`);
obj={name:"大海",age:18}
console.log(`name:${obj.name},age:${obj.age}`);
複製代碼

即便對象的內容沒改變,指針改變了也是不能夠的 image.pngapp

箭頭函數和普通函數的區別

  • 箭頭函數不須要 function 關鍵字來建立函數
  • 箭頭函數能夠省略 return 關鍵字
  • 箭頭函數繼承當前上下文的 this 關鍵字,定義的時候就肯定並固定了
  • 箭頭函數call、apply、bind 並不會影響其 this 的指向
  • 箭頭函數沒有原型prototype
  • 箭頭函數沒有本身的arguments

面試官深挖的問題

QQ圖片20210514095847.gif

1.call、apply和bind的區別

  • 三者均可以改變函數的this指向,經過第一個參數來綁定
  • 三者的第一個參數若是爲null、undefined的時候,默認指向window(在瀏覽器中)
  • call第二個參數是參數列表,applay是數組,bind傳入的也是一個參數列表(可是這個參數列表能夠分屢次傳入,applycall是一次性傳入全部參數)
  • bind 改變this指向後不會當即執行,而是返回一個永久改變this指向的函數來讓咱們手動調用; apply, call則是當即調用

2.箭頭函數的this是怎麼肯定的

var name = '小度'
function b(){
    console.log(this); // window
    var name = '小白'
    c =()=>{
        console.log(this.name)  ;
    }
    c()
}
b()
複製代碼

image.png 這裏箭頭函數c是在普通函數b中定義的,因此箭頭函數c的this是指向普通函數b的this的,這裏普通函數的this是全局(window),這個須要在瀏覽器環境下執行,在node環境下執行是undefined異步

Promise的靜態方法和實例方法

注:這裏有些公司會涉及手寫Promise,你們能夠去研究源碼實現和手寫一下。這個知識點很重要,高頻考點中高頻考點,你們必定要注意了啊!
1.首先了解Promise的三種狀態async

  • pending 待定
  • fulfilled/resolved 兌現/解決/成功
  • rejected 拒絕/失敗

2.Promise對象的狀態改變,只有兩種可能:

  • pending變爲fulfilled
  • pending變爲rejected

注意:這兩種狀況只要發生,狀態就肯定了,不會再變了。

靜態方法

  • 1.Promise.resolve

resolve : 將Promise對象的狀態從 Pending(待定) 變爲 Fulfilled(成功)

new Promise(resolve => {
      resolve('hello 大海')
  }).then(res => {
    console.log(res)
  })
複製代碼
  • 2.Promise.reject

reject : 將Promise對象的狀態從 Pending(待定) 變爲 Rejected(失敗)

new Promise(reject => {
    reject('hello 大海')
}).then(res => {
  console.log(res)
})
複製代碼
  • 3.Promise.all
    • 好比當數組裏的p1,p2,p3,p4都執行完成時,頁面才顯示。

    • 值得注意的是,返回的數組結果順序不會改變,即便P2的返回要比P1的返回快,順序依然是p1,p2,p3,p4

    • Promise.all成功返回成功數組,失敗返回失敗數據,一但失敗就不會繼續往下走

let p1 = Promise.resolve('p1')
        let p2 = Promise.resolve('p2')
        let p3 = Promise.resolve('p3')
        let p4 = Promise.resolve('p4')
        Promise.all([p1, p2, p3, p4]).then(res => {
            console.log('成功', res); //返回數組
        }).catch(err => {
            console.log('失敗', err);
        })

複製代碼
  • 4.Promise.race

Promise.race是賽跑的意思,也就是說Promise.race([p1, p2, p3,p4])裏面的結果哪一個獲取的快,就返回哪一個結果,無論結果自己是成功仍是失敗

let p1 = Promise.resolve('p1')
let p2 = Promise.resolve('p2')
let p3 = Promise.reject('p3')
let p4 = Promise.resolve('p4')
Promise.race([p1, p2, p3, p4]).then(res => {
    console.log('成功', res); //返回數組
}).catch(err => {
    console.log('失敗', err);
})
複製代碼
  • 5.Promise.allSettled //ES11的新特性
    • 該方法返回一個在全部給定的promise都已經fulfilled或rejected後的promise,並帶有一個對象數組,每一個對象表示對應的promise結果。

    • 當您有多個彼此不依賴的異步任務成功完成時,或者您老是想知道每一個promise的結果時,一般使用它。

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];

Promise.allSettled(promises).
  then((results) => results.forEach((result) => console.log(result.status)));
複製代碼

image.png 實例方法(原型方法)

  • 1.Promise.prototype.then

該方法能夠接收兩個回調函數做爲參數,其中第二個回調函數是可選的。第一個回調函數是 Promise 對象的狀態變爲 Resolved 時調用,第二個回調函數是 Promise 對象的狀態變爲 Rejected 時調用。

var p1 = new Promise((resolve, reject) => {
  resolve('成功!');
  // or
  // reject(new Error("出錯了!"));
});

p1.then(value => {
  console.log(value); // 成功!
}, reason => {
  console.error(reason); // 出錯了!
});
複製代碼
  • 2.Promise.prototype.catch

該方法返回一個Promise,而且只處理拒絕(rejected )的狀況。

const p = new Promise((resolve, reject)=>{
    reject('失敗了')
  }).catch(err=>{
      console.log(err);
  })
  
複製代碼
  • 3.Promise.prototype.finally

該方法,不管上一個promise 成敗都會執行,且默認狀況下會原樣傳遞上一個 promise 的決議,可是finally 對自身返回的 promise 的決議影響有限,它能夠將上一個 resolve 改成 reject,也能夠將上一個 reject 改成另外一個 reject,但不能把上一個 reject 改成 resolve默認狀況

var p = Promise.resolve('ok')
.finally((res) => { 
  return res })
.then(value => {
  console.log('成功', value)
}, (err) => {
  console.log('失敗', err)
});
複製代碼

將上一個 resolve 改成 reject

var p = Promise.resolve('ok')
.finally(() => { 
  return Promise.reject('err') })
.then(value => {
  console.log('成功', value)
}, (err) => {
  console.log('失敗', err)
});
複製代碼

面試官深挖的問題

QQ圖片20210514095847.gif then有幾個參數,then第二個參數和catch的區別是什麼?

這裏我面試官先問的是then有幾個參數,我回答的是1個;接着面試官就問then第二個參數和catch的區別是什麼?這時我就知道本身打錯了,哎!因此後面這個問題我確定也是答不出來的。

image.png 接下來就爲你們解答吧!

then方法能夠接受兩個回調函數做爲參數。其中,第二個函數是可選的,不必定要提供。這兩個函數都接受Promise對象傳出的值做爲參數。then方法返回的是一個實例(不是原來那個Promise實例)

區別

  • 區別1 最主要區別就是then中第一個函數裏拋出的異常,它的第二個函數是捕獲不到異常的,後面的catch能夠捕獲到(或者第二個then的第二個函數也能夠捕獲到);

  • 區別2且then的第二個參數和catch捕獲異常時會採起就近原則,當二者都存在時,則只有then的第二個參數能捕獲到,若是then的第二個參數不存在,則catch方法會捕獲到;

用代碼展現一下then第二個參數和catch的區別

const p = new Promise((resolve, reject)=>{
    resolve('對了')
  })
  p.then((res)=>{
    throw new Error('hello'); 
  },(err)=>{
      console.log(err,'第一個then捕獲錯誤');
  }).catch((err1)=>{
    console.log(err1,'catch捕獲錯誤');
  })
複製代碼

image.png 咱們能夠發現then中的第二個函數沒法捕獲到自身第一個函數拋出的異常,catch則能夠捕獲的獲得 若是把catch刪除,那麼就會報錯

const p = new Promise((resolve, reject)=>{
    resolve('成功了')
  })
  p.then((res)=>{
    throw new Error('hello'); 
  },(err)=>{
      console.log(err,'第一個then捕獲錯誤');
  })
複製代碼

image.png

也能夠在繼續使用then來捕獲上一個then中拋出的錯誤

const p = new Promise((resolve, reject)=>{
    resolve('成功了')
  })
  p.then((res)=>{
    throw new Error('hello'); 
  },(err)=>{
    console.log(err,'第一個then捕獲錯誤');
  }).then((res)=>{},(err1)=>{
    console.log(err1,'第二個then捕獲錯誤');
  })
複製代碼

image.png

就近原則捕獲異常,就是區別2

const p = new Promise((resolve, reject)=>{
    resolve('成功了')
  })
  p.then((res)=>{
    throw new Error('hello'); 
  },(err)=>{
    console.log(err,'第一個then捕獲錯誤');
  }).then((res)=>{},(err1)=>{
    console.log(err1,'第二個then捕獲錯誤');
  }).catch((err2)=>{
    console.log(err2,'catch捕獲錯誤');
  })
複製代碼

image.png

Promise和async/await的區別

  • promise是ES6,async/await是ES7
  • async/await相對於promise來說,寫法更加優雅
  • reject狀態:
    • 1)promise錯誤能夠經過catch來捕捉,建議尾部捕獲錯誤,
    • 2)async/await既能夠用.then又能夠用try-catch捕捉

Promise.all和 Promise.race的區別

區別

  • Promise.all成功返回成功數組,失敗返回失敗數據,一但失敗就不會繼續往下走
  • Promise.race是賽跑的意思,也就是說Promise.race([p1, p2, p3,p4])裏面的結果哪一個獲取的快,就返回哪一個結果,無論結果自己是成功仍是失敗

Promise.all

let p1 = Promise.resolve('p1')
        let p2 = Promise.resolve('p2')
        let p3 = Promise.reject('p3')
        let p4 = Promise.resolve('p4')
        Promise.all([p1, p2, p3, p4]).then(res => {
            console.log('成功', res); //返回數組
        }).catch(err => {
            console.log('失敗', err);
        })

複製代碼

image.png Promise.race

let p1 = Promise.reject('p1')
        let p2 = Promise.resolve('p2')
        let p3 = Promise.reject('p3')
        let p4 = Promise.resolve('p4')
        Promise.race([p1, p2, p3, p4]).then(res => {
            console.log('成功', res); //返回數組
        }).catch(err => {
            console.log('失敗', err);
        })
複製代碼

image.png

Promise與setTimeout結合猜輸出

console.log('start')
setTimeout(() => {
  console.log('time')
})
Promise.resolve().then(() => {
  console.log('resolve')
})
console.log('end')
複製代碼

分析

  • 剛開始整個腳本做爲一個宏任務來執行,對於同步代碼直接壓入執行棧進行執行,所以先打印出start和end。
  • setTimout做爲一個宏任務被放入宏任務隊列(下一個)
  • Promise.then做爲一個微任務被放入微任務隊列
  • 本次宏任務執行完,檢查微任務,發現Promise.then,執行它
  • 接下來進入下一個宏任務,發現setTimeout,執行。

image.png

推薦Promise相關題目:【建議星星】要就來45道Promise面試題一次爽到底(1.1w字用心整理)

總結

本人仍是大三學生,因爲時間和精力有限,就暫時更新到這,下篇將會盡快整理出來,但願你們能夠多多支持! 我如今也在不斷突破本身,特別是表達能力,但願你們共同進步吧!有問題能夠在評論區中指出來,在此先感謝你們!也能夠➕微信zxl814405253共同探討問題!

image.png

相關文章
相關標籤/搜索