本章內容一共分爲四大項,然後尋行漸近的說名,這四大項是 【創建對象有幾種方法】【原型、構造函數、實例、原型鏈】【instanceof原理】【new運算符】
一、創建對象的幾種方式
第1種:字面量
let n1 = {a: 1}
let n2 = new Object({a: 2})
第2種: 通過構造函數
let M = function(name){ this.name = name } let n3 = new M('a3')
第3種: Object.create創建
let p = {name: 'p'} let n4 = Object.create(p)
二、原型、構造函數、實例、原型鏈
首先我們來看一張圖片
說明:
- 每一個構造函數都有一個顯式原型(prototype)
- 每一個構造函數都有一個構造器
- 每一個實例都有一個隱式原型(__proto__)
- 實例的隱式原型(__proto__)指向構造函數的顯式原型(prototype)
- 構造函數的顯式原型的constructor指向是構造函數
附加:
(1)ES6中的class是函數的語法糖
(2)只有函數纔有prototype,對象沒有(函數也是對象)
(3)只有實例對象有__proto__,函數也有__proto,因爲函數也是對象xx.__proto__ === Function.prototype(返回true,xx代表函數)
(4)任何一個實例對象,通過原型鏈找到它上面的原型對象,那個上面的方法和屬性,都是被實例所共享的(這樣子可以避免在每個構造函數上都創建相同的方法,造成代碼冗餘)。
代碼演練:M是構造函數,n3是實例對象
let M = function(name){
this.name = name
}
let n3 = new M('a3')
我們再來看一張圖片(哈哈,本人手繪板,有點醜😂):
原型鏈原理:從一個實例對象往上找這個實例相關聯的原型對象,這個原型對象再往上找又有創造它的上一級的原型對象,以此類推,一直找到Object.prototype而終止。下面代碼可以說明問題,對應圖形見上圖。
class Animal{
constructor(name){
this.name = name
}
eat(){
console.log('我愛喫')
}
}
class Dog extends Animal{
constructor(name,age){
super(name)
this.age = age
}
say(){
console.log('我會汪汪叫')
}
}
let dog = new Dog('vip dog', 3)
三、instanceof原理
來來來,咱門再看一張圖,嘿嘿,我最喜歡看圖說話了!
- instanceof原理:是爲了判斷此實例或者構造器是否是父級繼承的。
- 判斷函數Animal是否是實例dog繼承的構造函數方法
- dog instanceof Animal === true
原理:dog.__proto__.[ __proto__ ···假設有n個__proto__··· ] === Animal.prototype
缺陷:這個方法不夠準確,因爲只要是同一條原型鏈上都是true,所以沒法證實dog實例最近的構造函數是哪個
例如:dog.__proto__.__proto__.__proto__ === Animal.prototype === Object.prototype
- 只有constructor才能確定dog實例是哪個最近的構造函數
dog.__proto__.constructor === Dog
看代碼演示:
class Animal{
constructor(name){
this.name = name
}
eat(){
console.log('我愛喫')
}
}
class Dog extends Animal{
constructor(name,age){
super(name)
this.age = age
}
say(){
console.log('我會汪汪叫')
}
}
let dog = new Dog('vip dog', 3)
</script>
左圖說明instanceof問題
左圖說明constructor問題
四、new運算符
new構造函數的原理:
- 生成一個空對象
- 將空對象的_proto_指向構造函數的prototype
- 執行構造函數,this上下文指向空對象
- 構造函數如果return了對象,放棄掉空對象;反之,返回前面的那個空對象