本文在個人主頁同步更新~
背就完事了
介紹:一些知識點相關的面試題和答案
使用姿勢:看答案前先嘗試回答,看完后把答案收起來檢驗成果~
面試官:什么是構造函數
答:構造函數的本質是一個普通函數,他的特點是需要通過new
關鍵字來調用,用來創建對象的實例。所有的引用類型,如[],{},function等都是由構造函數實例化而來。一般首字母大寫。
解析:首字母大寫只是約定俗成的規范。首字母小寫的函數也可以用作構造函數。
面試官:什么是原型和原型鏈
答:原型模式是JS實現繼承的一種方式。所有的函數都有一個prototype
屬性,通過new
生成一個對象時,prototype
會被實例化為對象的屬性。所有的引用類型都有一個__proto__
指向其構造函數的prototype
。原型鏈的話,指的就是當訪問一個引用類型時,如果本身沒有這個屬性或方法,就會通過__proto__
屬性在父級的原型中找,一級一級往上,直到最頂層為止。
解析:原型鏈最頂層Object的prototype
的__proto__
指向為null。
面試官:如何理解constructor
屬性
答:所有函數的原型對象都有一個constructor
屬性指向函數本身。
解析:實例化的對象可以通過[].__proto__.constructor
獲取到其構造函數。
面試官:描述new 操作符的執行過程
答:
- 創建一個空對象。
- 將這個空對象的
__proto__
指向構造函數的prototype
。 - 將構造函數的
this
指向這個對象。 - 執行構造函數中的代碼。
面試官:如何判斷一個變量是數組類型
答: 使用instanceof
關鍵字 或者constructor
屬性。
解析:instanceof
的原理是判斷操作符左邊對象的原型鏈上是否有右邊構造函數的prototype
屬性。
理解小幫手
介紹:總結性的圖表,代碼例子或筆試題目和解析,讓知識點更容易懂
關於構造函數和原型
構造函數:相當於java中“類”的存在,如原生JS中的Array, Function, String, Date
等等,都是構造函數。例如new Date()
通過new操作符進行調用,用來創建一個Date對象的實例。
一個便於理解的栗子,描述js通過原型模式實現繼承的過程
function Animal (name) { // 構造函數
this.name = name
}
Animal.prototype.type = 'animal' // 原型上的屬性和方法可以被繼承
Animal.prototype.eat = function () {
console.log('eat')
}
let dog = new Animal('忠犬八公') // 通過new 調用構造函數創建Animal的實例dog
console.log(dog.name) // 輸出:忠犬八公
console.log(dog.type) // 輸出:animal
dog.eat() // 輸出:eat
console.log(dog.__proto__) // 輸出:{ type:'animal', eat: f, __proto__: ...}
// dog.__proto__ 指向其構造函數Animal的prototype對象
一個關於原型的實用型例子
function Elem(id) {
this.elem = document.getElementById(id)
}
Elem.prototype.html = function (val) {
var elem = this.elem
if (val) {
elem.innerHTML = val
return this // 鏈式編程
}else{
return elem.innerHTML
}
}
Elem.prototype.on = function (type, fn) {
var elem = this.elem
elem.addEventListener(type, fn)
}
var div1 = new Elem('div1')
div1.html('灶門碳治郎').on('click', (e) => {
alert('灶門碳治郎')
})
這個栗子,使用原型將對dom
節點的操作封裝起來,只要創建一個Elem實例就輕松插入dom
和添加事件監聽。
原型鏈
所有的引用類型會有一個__proto__
屬性指向其構造函數的prototype
,當訪問這個引用類型的變量和方法時,會通過__proto__
屬性一層層往上找。如[]
不止有構造函數Array
原型上的方法,還有可以通過原型鏈找到Object
原型上的方法。
關於instanceof 和 constructor
instanceof
:判斷操作符右邊的參數是否在左邊的原型鏈上。所以[] instanceof Object
也為true
let obj = {}
let arr = []
console.log(typeof(obj)) // object
console.log(typeof(arr)) // object
console.log(obj instanceof Array) // false
console.log(arr instanceof Array) // true
console.log(obj.constructor === Array) // false
console.log(arr.constructor === Array) // true
通過以上代碼可以學習通過instanceof
關鍵字和constructor
屬性進行數據類型判斷的使用方式。
知識延伸
先有雞還是先有蛋
JS究竟是先有Object還是先有Function呢?
console.log(Function instanceof Object) // 輸出:true
console.log(Object instanceof Function) // 輸出:true
Object和Function究竟是什么關系,這個問題一度困擾着我,直到我看到了這張圖
簡單理解為:
Function
在Object
的原型鏈上,因為Object
是構造函數,他的__proto__
指向Function
的原型Object
在Function
的原型鏈上,因為Function
是構造函數,他的__proto__
指向的也是他自己的原型,然而Function.prototype
本質上是一個對象,所以Function.prototype.__proto__
指向Object.prototype
。
關於鏈式編程
上述“一個關於原型的實用例子”中,提到了鏈式編程,在此做簡單介紹
function Dog(){
this.run = function(){
alert('dog is run...')
return this // 鏈式編程的關鍵
}
this.eat = function(){
alert('dog is eat...')
return this
}
this.sleep = function(){
alert('dog is sleep...')
return this
}
}
var d1 = new Dog()
d1.run().eat().sleep()
通過以上代碼可以看出
- 鏈式編程的設計模式就是,調用的函數的時候,可以基於其返回值繼續調用其他方法。
- 關鍵在於方法執行結束后需要有一個供繼續調用的返回值,如
this
等。
Kane -- 一切都是命運石之門的選擇