原型
在 JavaScript 中喻喳,每創(chuàng)建一個對象另玖,該對象(null 除外)都與另一個對象有關,“另一個對象” 說的就是原型(也稱為原型對象)表伦,每個對象都從原型繼承屬性和方法谦去。
原型鏈
- 每個實例都包含一個指向其原型對象的指針,而每個原型對象都包含一個指向其構造函數(shù)的指針蹦哼,這樣一來就形成了一條鏈鳄哭,我們稱之為 原型鏈;
- 原型鏈查找機制:當我們通過
對象名.屬性名
或對象名.方法名
訪問對象時屬性或方法時纲熏,JavaScript 會先在當前對象尋找該屬性或方法妆丘,如果當前對象沒有該屬性或方法,JavaScript 就到其原型對象上找局劲,直到Object.prototype
勺拣,如果此時還是沒有找到該屬性或方法,就會返回undefined
鱼填;- 當我們通過
對象名.prototype.屬性名
或對象名.prototype.方法名
為對象添加屬性或方法時药有,其實我們是在其原型上添加了該屬性或方法,因此剔氏,所有通過該原型實例化的對象均擁有該屬性或方法塑猖。
當我們創(chuàng)建一個 Array
對象:
var arr = [1, 3, 5, 8];
其原型鏈如下:
arr --> Array.prototype --> Object.prototype --> null
我們在控制臺輸出 console.dir(Array.prototype);
,看看得到什么:
緊接著我們同樣在控制臺輸出 console.dir(arr);
谈跛,看看得到什么:
可以看到羊苟,Array.prototype
這個原型里面有許多的屬性和方法,例如:用來獲取數(shù)組長度的 length
屬性感憾、往數(shù)組后面添加元素的 push()
方法蜡励,同樣的,arr
也有這些屬性和方法阻桅。所以凉倚,所有從 Array.prototype
這個原型繼承的對象都有該原型所擁有的屬性和方法。
原型繼承
繼承是面向?qū)ο笳Z言的一種重要特征嫂沉,作為一門面向?qū)ο笳Z言稽寒,JavaScript 當然也有繼承這個概念,只不過 JavaScript 的繼承主要是靠 原型鏈 來實現(xiàn)趟章。
下面通過一個例子來了解一下杏糙。
代碼:
<script>
// Ⅰ. Parent 的構造函數(shù)
function Parent(who) {
this.who = who;
}
// Ⅱ. 為 Parent 的原型添加方法
Parent.prototype.say = function () {
console.log('I am ' + this.who);
};
// Ⅲ. Children 的構造函數(shù)
function Children(who) {
this.who = who;
}
// Ⅳ. 實例化一個 Parent 的對象
var parent = new Parent('parent');
// Ⅴ. Parent 的實例作為 Children 的原型對象
Children.prototype = parent;
// Ⅵ. 實例化一個 Children 的對象
var children = new Children('children');
// Ⅶ. 調(diào)用 children 的 say() 方法
children.say();
</script>
效果演示:
結果分析:
- 在 Ⅶ 中我們調(diào)用了 children 對象的
say()
方法慎王,但是我們并沒有給 children 這個對象定義這樣一個方法,根據(jù)原型鏈查找機制宏侍,JavaScript 會往其構造函數(shù)里找赖淤; - 在 Ⅲ Children 的構造函數(shù)中也沒有找到
say()
這個方法,這時就會往其原型上找谅河; - 在 Ⅴ 中咱旱,我們發(fā)現(xiàn) Children 的原型是 Parent 的實例,所以绷耍,繼續(xù)往 Parent 的構造函數(shù)里找吐限,這時來到了 Ⅰ;
- 在 Ⅰ 中褂始,我們發(fā)現(xiàn) Parent 的構造函數(shù)里也沒有
say()
這個方法毯盈,所以,繼續(xù)往其原型上找病袄; - 在 Ⅱ 中,也就是 Parent 的原型上赘阀,我們找到了
say()
這個方法益缠,這時,查找結束基公,返回該方法幅慌。
以上就是 JavaScript 中的原型繼承的基本原理。當然轰豆,原型繼承只是 JavaScript 中繼承方式的一種胰伍,但也是用得比較多的一種。
另外: \_\_proto__
指向的是構造函數(shù)酸休,prototype
指向的是原型骂租。
參考資料: