JavaScript深入理解 —— 原型壁袄、原型鏈和繼承

普通對象和函數(shù)對象

函數(shù)對象:使用函數(shù)聲明类早、函數(shù)表達式Function構(gòu)造函數(shù)創(chuàng)建的對象

函數(shù)實際上是對象嗜逻,每個函數(shù)都是Function類型的實例涩僻,而且都與其他引用類型一樣具有屬性和方法。

普通對象:除了函數(shù)對象以外的對象栈顷,都是普通對象逆日。

示例:

// 定義函數(shù)的三個方法
function f1() {};       // 函數(shù)聲明
var f2 = function() {};         // 函數(shù)表達式
var f3 = new Function("num1", "num2", "return num1 + num2");        // Function構(gòu)造函數(shù)

// 創(chuàng)建對象
var o1 = {};        // 對象字面量
var o2 = new Object();      // Object構(gòu)造函數(shù)
var o3 = new f1();      // f1構(gòu)造函數(shù)

// 檢測類型
console.log(typeof Function);  //function
console.log(typeof Object);  //function

console.log(typeof f1);  //function
console.log(typeof f2);  //function
console.log(typeof f3);  //function

console.log(typeof o1);  //object
console.log(typeof o2);  //object
console.log(typeof o3);  //object

構(gòu)造函數(shù)

構(gòu)造函數(shù): 通過new關(guān)鍵字方式調(diào)用的函數(shù)。

在構(gòu)造函數(shù)內(nèi)部(也就是被調(diào)用的函數(shù)內(nèi)):

  1. this 指向?qū)嵗龑ο?Object萄凤;
  2. 這個實例對象的 __proto__ 屬性指向構(gòu)造函數(shù)的 prototype室抽;
  3. 這個實例對象的constructor屬性指向構(gòu)造函數(shù)
  4. 如果被調(diào)用的函數(shù)沒有顯式的 return 表達式靡努,則隱式的會返回 this 對象 —— 也就是實例對象坪圾。

示例:

function Person(name) {
    this.name = name;
    this.sayName = function() {
        console.log(this.name);
    };
}
var person1 = new Person("Hysunny");
var person2 = new Person("Max");

console.log(person1 instanceof Person);     // true
console.log(person1.constructor === person2.constructor);       // true

// 實例的__proto__屬性指向構(gòu)造函數(shù)的prototype
console.log(person1.__proto__ === Person.prototype);        // true

// 實例的constructor指向構(gòu)造函數(shù)
console.log(person1.constructor === Person);        // true

原型對象

在 JavaScript 中,每當(dāng)定義一個對象(函數(shù))時候颤难,對象中都會包含一些預(yù)定義的屬性。其中就包含prototype屬性已维,這個屬性指向函數(shù)的原型對象行嗤。

  1. 原型對象是一個普通對象(除Function.prototype之外),存儲所有實例對象共享的方法和屬性垛耳;
  2. 構(gòu)造函數(shù)原型對象是構(gòu)造函數(shù)的一個實例栅屏。
  3. 原型對象的constructor屬性指向prototype屬性所在的函數(shù);
  4. 每個對象都有 __proto__ 屬性堂鲜,但只有函數(shù)對象才有 prototype 屬性栈雳,這兩個屬性指向函數(shù)的原型對象

示例:

function Person(name) {
  this.name = name;
}

Person.prototype. sayName = function() {
  console.log(this.name);
}

var person1 = new Person("Hysunny");
var person2 = new Person("Max");

// 構(gòu)造函數(shù)缔莲、原型對象和實例之間有這樣的聯(lián)系
Person.prototype.constructor === Person;
person1.__proto__ === Person.prototype;
person1.constructor === Person;

console.log(person1.constructor === Person);        // true
console.log(Person.prototype.constructor === Person);       // true
console.log(Person.prototype.constructor === person1.constructor);      // true
// => 原型對象是構(gòu)造函數(shù)的一個實例

console.log(Person.prototype.constructor == Person);        // true
// => 原型對象的constructor屬性指向prototype屬性所在的函數(shù)

console.log(person1.__proto__ === Person.prototype);        // true
// => __proto__屬性指向函數(shù)的原型對象

注: Function.prototype雖為函數(shù)對象哥纫,但是是個空函數(shù),沒有prototype屬性痴奏。

console.log(typeof Function.prototype) // function
console.log(typeof Function.prototype.prototype) // undefined

原型鏈

從上面的分析我們可以知道:JS在創(chuàng)建對象(不論是普通對象還是函數(shù)對象)的時候蛀骇,都有一個__proto__內(nèi)置屬性厌秒,用于指向創(chuàng)建它的函數(shù)對象的原型對象prototype

以上面的例子為例:

  1. person1具有__proto__屬性擅憔,指向Person.prototype
  2. Person.prototype具有__proto__屬性鸵闪,指向Object.prototype
  3. Object.prototype具有__proto__屬性,指向null
console.log(person1.__proto__ === Person.prototype) // true
console.log(Person.prototype.__proto__ === Object.prototype) // true
console.log(Object.prototype.__proto__) // null

這些__proto__串起來暑诸,就構(gòu)成了原型鏈蚌讼,原型鏈的頂端為null。繪出原型鏈圖如下:

prototype-chain.png

簡化如下:

prototype.png

疑點解釋:

1. Object.__proto__ === Function.prototype  // true
// Object是函數(shù)對象个榕,是通過new Function()創(chuàng)建篡石,所以O(shè)bject.__proto__指向Function.prototype。

2. Function.__proto__ === Function.prototype        // true
// Function 也是對象函數(shù)笛洛,也是通過new Function()創(chuàng)建夏志,所以Function.__proto__指向Function.prototype。

3. Function.prototype.__proto__ === Object.prototype // true
// Function本身也是一個構(gòu)造函數(shù)苛让,所以`Function.prototype.__proto__`指向`Object.prototype`

繼承

繼承是OO語言中的一個最為人津津樂道的概念.許多OO語言都支持兩種繼承方式: 接口繼承實現(xiàn)繼承 沟蔑。接口繼承只繼承方法簽名,而實現(xiàn)繼承則繼承實際的方法.由于js中方法沒有簽名,在ECMAScript中無法實現(xiàn)接口繼承.ECMAScript只支持實現(xiàn)繼承,而且其 實現(xiàn)繼承 主要是依靠原型鏈來實現(xiàn)的.

為什么要實現(xiàn)繼承呢?

最重要的原因之一就是為了抽象(復(fù)用代碼)狱杰。

將公共的代碼封裝成一個基類瘦材,其他子類繼承基類,并發(fā)展自己特有的屬性和樣式仿畸。

關(guān)于實現(xiàn)繼承的方式食棕,我們將在下一篇文章中進行討論。


參考資料:

《JavaScript 高級程序設(shè)計》 第三版

js原型與原型鏈終極詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末错沽,一起剝皮案震驚了整個濱河市簿晓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌千埃,老刑警劉巖憔儿,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異放可,居然都是意外死亡谒臼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門耀里,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蜈缤,“玉大人,你說我怎么就攤上這事冯挎〉赘纾” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長叠艳。 經(jīng)常有香客問我奶陈,道長,這世上最難降的妖魔是什么附较? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任吃粒,我火速辦了婚禮,結(jié)果婚禮上拒课,老公的妹妹穿的比我還像新娘徐勃。我一直安慰自己,他們只是感情好早像,可當(dāng)我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布僻肖。 她就那樣靜靜地躺著,像睡著了一般卢鹦。 火紅的嫁衣襯著肌膚如雪臀脏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天冀自,我揣著相機與錄音揉稚,去河邊找鬼。 笑死熬粗,一個胖子當(dāng)著我的面吹牛搀玖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播驻呐,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼灌诅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了含末?” 一聲冷哼從身側(cè)響起猜拾,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎佣盒,沒想到半個月后挎袜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡沼撕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年宋雏,在試婚紗的時候發(fā)現(xiàn)自己被綠了芜飘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片务豺。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嗦明,靈堂內(nèi)的尸體忽然破棺而出笼沥,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布奔浅,位于F島的核電站馆纳,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏汹桦。R本人自食惡果不足惜鲁驶,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望舞骆。 院中可真熱鬧钥弯,春花似錦、人聲如沸督禽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽狈惫。三九已至睛蛛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間胧谈,已是汗流浹背忆肾。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留第岖,地道東北人难菌。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像蔑滓,于是被迫代替她去往敵國和親郊酒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 理解 javascript 的原型鏈及繼承 以上所有的運行結(jié)果都是 true; 三種構(gòu)造對象的方法: 通過對象字面...
    你期待的花開閱讀 1,505評論 0 3
  • 原型鏈?zhǔn)且环N機制键袱,指的是 JavaScript 每個對象都有一個內(nèi)置的 __proto__ 屬性指向創(chuàng)建它的構(gòu)造函...
    劼哥stone閱讀 4,405評論 15 80
  • 前言 原型燎窘,作為前端開發(fā)者,或多或少都有聽說蹄咖。你可能一直想了解它褐健,但是由于各種原因還沒有了解,現(xiàn)在就跟隨我來一起探...
    無亦情閱讀 662評論 0 8
  • 在JS中澜汤,原型鏈?zhǔn)且粋€重要的概念蚜迅,不管是繼承還是屬性值的查找中,都用到了原型鏈的基本知識俊抵,有些朋友經(jīng)常問我一些關(guān)于...
    彬_仔閱讀 1,587評論 2 20
  • (宵夜)三更夜悄靜谁不,入夜了無聲。追追連續(xù)劇徽诲,看看戰(zhàn)爭片刹帕。肚饑腹中響吵血,尋塊咸餅干。加杯熱奶茶偷溺,平慰小腹空蹋辅。
    甘朝武閱讀 270評論 0 0