前端JS面試題-基礎-作用域和閉包
阿新 • • 發佈:2021-07-11
寫在前面:本文內容主要根據慕課網雙越老師的付費課程“一天時間迅速準備前端面試 快速構建初級前端知識體系 ”進行編寫,主要是為了自己在面試前總結學習,歡迎留言指教。
本文包括如下內容:
每一部分包括題目和知識點兩部分。
作用域和閉包
題目
- this的不同應用場景,如何取值
- 手寫bind函式
- 實際開發中閉包的應用場景,舉例說明
- 場景題
1. this的不同應用場景,如何取值
有5種應用場景,如下:
- 作為普通函式——返回window
- 使用 call apply bind——傳入什麼繫結什麼
- 作為物件方法被呼叫——返回物件本身
- 在class方法中呼叫——當前例項本身
- 箭頭函式——上級作用域
2. 手寫bind函式
bind() 方法會建立一個新函式,當這個新函式被呼叫時,它的 this 值是傳遞給 bind() 的第一個引數, 它的引數是 bind() 的其他引數和其原本的引數。
//模擬 bind Function.prototype.bind1 = function () { // 將引數拆解為陣列 const args = Array.prototype.slice.call(arguments) //獲取 this (陣列第一項) const t = args.shift() // fn1.bind(···)中的 fn1 const self = this //返回一個函式 return function () { return self.apply(t, args) } } // 使用 function fn1(a, b, c) { console.log('this', this) console.log(a, b, c) return 'this is fn1' } const fn2 = fn1.bind1({x: 100}, 10, 20, 30) console.log(fn2()) // 結果 this {x: 100} 10 20 30 this is fn1
3. 實際開發中閉包的應用場景,舉例說明
- 函式作為返回值,以cache快取為例:
function createCache() { const data = {} //閉包中的資料被隱藏,不被外界訪問 return { set: function (key, val) { data[key] = val }, get: function (key) { return data[key] } } } const c = createCache() c.set('a', 100) console.log(c.get('a'))
- 函式作為引數被傳遞,以setTimeout定時器為例:
function fn() {
alert()
}
const func = fn()
// 第一個引數是一個函式,或者是一段執行的js程式碼,第二引數是第一個引數執行的時間間隔。
setTimeout(func, 1000)
被面試官問到什麼是閉包,最好的回答就是把兩個 demo 寫一遍,然後說出閉包的使用場景【cache快取 setTimeout定時器 非同步操作 等】。不用說什麼概念。
4. 場景題
這個程式碼打印出來的序號都是 10,應該在for裡定義let i,這樣需要都是遞增的。
知識點
1. 作用域
- 全域性作用域
- 函式作用域
- 塊級作用域(ES6新增)【大括號內是一個塊級作用域】
2. 自由變數【當前作用域未定義的變數】
- 一個變數在當前作用域沒有定義,但被使用了
- 向上級作用域,一層一層一次尋找,直至找到為止
- 如果到全域性作用域都沒找到,則報錯 xx is not defined
所有的自由變數的查詢,是在函式定義的地方,向上級作用域查詢,不是在執行的地方!!!
3. 閉包
作用域引用的特殊情況,有兩種表現:
- 函式作為引數被傳遞
- 函式作為返回值被返回
4. this
有5種應用場景,如下:
- 作為普通函式——返回window
- 使用 call apply bind——傳入什麼繫結什麼
- 作為物件方法被呼叫——返回物件本身
- 在class方法中呼叫——當前例項本身
- 箭頭函式——上級作用域
// 普通函式:返回window
function fn1() {
console.log(this)
}
fn1() //window
// call apply bind:傳入什麼繫結什麼
fn1.call({x: 100}) //{x: 100}
const fn2 = fn1.bind({x:200})
fn2() //{x:200}
// 作為物件方法被呼叫:返回物件本身
const zhangsan = {
name: '張三',
sayhi(){
console.log(this)
}
}
zhangsan.sayhi() //{name: "張三", sayhi: ƒ}
// 在class方法中呼叫:返回例項本身
class People{
constructor(name){
this.name = name
}
sayhi(){
console.log(this)
}
}
const zhangsan = new People('張三')
zhangsan.sayhi() //People{name: "張三"}
// 箭頭函式:上級作用域
const zhangsan = {
name: '張三',
wait(){
setTimeout(()=>{
console.log(this)
})
},
waitAgain(){
setTimeout(function () {
console.log(this)
})
}
// 兩個函式進行對比
}
zhangsan.wait() //{name: "張三", wait: ƒ, waitAgain: ƒ}
zhangsan.waitAgain() //window
this取什麼值,是在函式執行的時候確認的,不是在函式定義的時候確認的