1. 程式人生 > >原型、原型對象、構造函數、原型鏈理解

原型、原型對象、構造函數、原型鏈理解

text 接收 所有 標註 情況 會有 屬性 es5 一個

1. 基本概念:

“原型屬性”也可以叫做“原型”(prototype):所有函數都有prototype,我覺得可以理解為python中的類屬性,不需要通過實例,直接用類(es5就是函數名)可以調用,下面列舉了三種創建函數的方法,函數創建後都有prototype屬性,prototype指向“原型對象”。

// 函數聲明
function F1() {
};
// 表達式定義
let F2 = function () {
};
// 函數構造
let F3 = new Function(‘n1‘, ‘n2‘, ‘return n1+n2‘);

console.info(F1.prototype)    //F1 {}
console.info(F2.prototype) //F2 {} console.info(F3.prototype) //anonymous {}

原型對象(prototype所指向的對象):這玩意主要就是用來繼承用的,包含實例的方法和屬性。說白了也就是一個對象,用來定義函數對象的屬性、方法,默認情況下它包含一個constructor屬性,如果你重新定義可以覆蓋constructor屬性。

原型對象與構造函數配合一起,就形成一個類了,然後構造函數接收每次初始化對象的初始值,原型對象就提供類模板。而在其他java、python中都寫在class中,當然es6也加入了class;以下的簡單代碼幫助理解上面說的,定義一個動物類,根據構造函數創造不同的動物,如果需要創建特殊動物,可以繼承然後添加一些特殊屬性、方法再創建。---------總結es5的類可以用“構造函數+構造函數的prototype”來定義,類的對象使用“new構造函數”來生成。

// 構造函數
let Animal = function (name) {
    this.name = name
}
// 原型對象定義
Animal.prototype.getAnimal = function () {
    return this.name
}
// 創建對象,會繼承Animal.prototype
let dog = new Animal(‘dog‘)
let cat = new Animal(‘cat‘)
console.info(dog.getAnimal())
console.info(cat.getAnimal())

技術分享圖片

上圖展示了構造函數、原型對象、具體對象的屬性、方法及屬性值。

普通對象與函數對象:通過函數對象 new一下可以得到普通對象,把函數對象理解為類,普通對象為實例。如下代碼加強理解,可以看到函數對象new完以後生產的對象是object;函數對象中都有prototype前面已經說過了(為什麽函數對象中會有這個屬性以後讀取更深以後再解答)

// Animal函數對象
let Animal = function (name) {
    this.name = name
}
// 原型對象
Animal.prototype.getAnimal = function () {
    return this.name
}
// 通過函數對象創建普通對象
let dog = new Animal(‘dog‘)
console.info(typeof dog)    //object

總結: 函數對象通過new Function()可以得到,Function對象可以構造函數對象。而函數對象又可以new一個普通對象出來。

__proto__:所有對象都有__proto__這個屬性,這個屬性指向對應“函數對象(就理解為類)”的prototype,這也是實現原型鏈的根本,在書中一般都用[[prototype]]。

構造函數和constructor屬性:其實前面的圖已經標註了,概念後續補上。

原型鏈:ES中的繼承主要用原型鏈來實現,記住了這玩意主要用來實現繼承。其基本思想是:利用原型讓一個引用類型繼承另一個引用類型的屬性和方法(js高級程序設計說的),還是用以上的例子來說明

let Animal = function (name) {
    this.name = name
}
// 原型對象定義
Animal.prototype.getAnimal = function () {
    return this.name
}
// 創建對象,會繼承Animal.prototype
let dog = new Animal(‘dog‘)
let cat = new Animal(‘cat‘)
console.info(dog.valueOf())
console.info(cat.valueOf())

跟上面例子就差了最後console打印部分,我們定義的Animal沒有寫valueof()為什麽可以調用這個方法呢?到底是什麽鬼?這就是原型鏈搞的鬼。我再把上面的圖形完善一下

上圖還有兩個屬性的指向沒有畫,第一、Animal的__proto__指向;第二、Animal.prototype的__proto__指向。

技術分享圖片

這個圖把Animal.prototype的__proto__指向添加了,

圖形說明:

1. Animal.prototype是個普通對象,ES中Object是所有對象的基礎。所有引用類型都繼承了Object;所有函數的默認原型是都Object的實例,因此Animal.prototype的__proto__指向Object.prototype,這個一定要理解。

2. 我們調用cat.valueOf()解釋器會先找dog實例中有沒有這個方法,沒有就在Animal.prototype中查找,沒有再去Object.prototype中查找。然後就有了cat.valueOf()的運行結果:Animal { name: ‘cat‘ }。

3. Object構造函數的prototype也指向Object.prototype。

原型、原型對象、構造函數、原型鏈理解