JS 原型沪么、原型鏈捅位、繼承

原型

簡單創(chuàng)建一個構(gòu)造函數(shù)與實例:

function Person() {

}
Person.prototype.name = 'Zhar';
Person.prototype.age = 30;
Person.prototype.say = function(){
  console.log(this.name);
}
var person1 = new Person();
var person2 = new Person();
console.log(person1.name) // Zhar
console.log(person2.name) // Zhar

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

person 是 Person 的一個實例對象

instanceof

instanceof 用于判斷一個對象是否是另一個對象的實例(該方法在原型鏈中依然有效)

console.log(person1 instanceof Person);//true
console.log(person2 instanceof Person);//true
var arr = new Array();
console.log(arr instanceof Array);//true

prototype

每個函數(shù)都有一個 prototype屬性(只有函數(shù))

prototype 指向腔召?

函數(shù)的 prototype屬性指向了一個對象杆查,這個對象就是調(diào)用該構(gòu)造函數(shù)而創(chuàng)建的實例的原型,也就是上面代碼中的 person1 person2的原型對象臀蛛。使用原型對象的好處就是可以讓把有對象的實例共享它所包含的屬性和方法亲桦。換句話說,不必在構(gòu)造函數(shù)中定義對象實例的信息浊仆,而是可以將這些信息直接添加到原型對象中去客峭。

constructor

默認(rèn)情況下,所有原型對象都會自動獲得一個 constructor(構(gòu)造器)屬性氧卧,這個屬性指向所在的函數(shù)桃笙。

Person.prototype.constructor 指向 Person

任何情況下,只要創(chuàng)建了一個新函數(shù)沙绝,就會為該函數(shù)創(chuàng)建一個 prototype 屬性搏明,這個屬性指向函數(shù)的原型對象鼠锈。

"原型"是什么?

每一個對象都有一個與之關(guān)聯(lián)的另一個'原型'對象星著,每一個對象都會從原型繼承屬性

如何訪問對象的原型购笆?

在 ECMA中,并沒有規(guī)定直接訪問對象原型的方法虚循,但 Firefox/Chrome/safari 在每一個對象都支持一個__proto__用來訪問對象的原型同欠。

__proto__

console.log(Person.prototype);
console.log(person);
console.log(person.__proto__);

__proto__存在于實例與構(gòu)造函數(shù)的原型對象之間,而不是存在于實例與構(gòu)造函數(shù)之間

isPrototypeOf

可通過object1.isPrototypeOf(object2)來判斷一個對象是否存在于另一個對象的原型鏈中横缔,即 object1 是否存在于 object2的原型鏈中铺遂。換句話講:判斷 object2是否有一個指針指向 object1

Person.prototype.isPrototypeOf(person1);//true
Person.prototype.isPrototypeOf(person2);//true

getPrototypeOf(ES5)

返回一個對象的原型

Object.getPrototypeOf(person1);
Object.getPrototypeOf(person2);

一些判斷

person.__proto__ === Person.prototype;//true
person.__proto__.constructor === Person.prototype.constructor;//true
person1.__proto__ === person2.__proto__;//true
person1.say === person2.say;//true
Object.getPrototypeOf(person1) === Object.getPrototypeOf(person2);//true
Object.getPrototypeOf(person1) === Person.prototype;//true

hasOwnProperty

觀察下面的代碼:

console.log(pserson1.name);//Zhar   來自于原型
console.log(person1.address);//undefined
person1.name = "new Name";
console.log(person1.name);//new Name   來自于實例
console.log(person2.name);//Zhar   來自于原型

尋找規(guī)則?

當(dāng)代碼讀取某個對象的某個屬性時茎刚,首先會從實例本身開始襟锐,如果在實例中找到了該屬性,則返回該屬性的值膛锭;如果沒有找到粮坞,則搜索指針指向的原型對象,如果找到初狰,則返回值莫杈,如果沒有則繼續(xù)向上尋找,直到找到 Obejct

雖然可以通過對象實例訪問原型中的值奢入,但不能通過對象實例重寫原型中的值筝闹。

如果在實例中添加了一個屬性,而該屬性與實例原型中的一個屬性名相同俊马,則會在實例中創(chuàng)建該屬性丁存,該屬性將會屏蔽原型中的那個同名屬性(可以通過 delete 刪除實例屬性,恢復(fù)原型屬性的訪問)

delete person1.name;
console.log(person1.name);//Zhar 來自于原型

通過hasOwnProperty(propertyName)來檢測一個屬性是存在于實例還是原型中

console.log(person1.hasOwnProperty("name"));//false;
person1.name = "newName";
console.log(person1.hasOwnProperty("name"));//true

in

觀察以下代碼:

console.log("name" in person1);//true;
person1.name = "newName";
console.log("name" in person1);//true

通過in關(guān)鍵字可以判斷某個對象是否包含某個屬性柴我,而不管這個屬性是屬于實例還是原型

通過 hasOwnProperty() 與 in 相結(jié)合解寝,可精確定位一個屬性是屬于原型還是實例

keys(es5)

keys(object)方法可返回對象所有可枚舉屬性的字符串?dāng)?shù)組

console.log(Object.keys(person1));//[]
person1.name = "newName";
console.log(Object.keys(person1));//["name"]
console.log(Object.keys(Person.prototype));//[ 'name', 'age', 'say' ]

keys()返回的是該對象的屬性數(shù)組,并不包含其構(gòu)造函數(shù)上的屬性

通過字面量對象創(chuàng)建原型的問題艘儒?

繼承

原型鏈?zhǔn)嚼^承

讓一個函數(shù)的原型對象指向另一個原型的指針聋伦,而另一個原型中也包含指向另外一個構(gòu)造函數(shù)的指針,依此層層嵌套界睁,形成原型鏈

function Animal() {
    this.topType = "脊椎動物";
}
Animal.prototype.getTopType = function(){
    return this.topType;
}
function Person() {
    this.secondType = "人類";
}

Person.prototype = new Animal();
Person.prototype.getSecondType = function(){
    return this.secondType;
}
var person = new Person();
console.log(person.topType+"--"+person.secondType);//脊椎動物--人類

在上面的例子中觉增,Person.prototype=new Animal() 即是將 Animal 實例賦給了 Person.prototype

結(jié)合前面原型中的講解,new Animal 產(chǎn)生一個 Animal 實例翻斟,該實例對象有一個__proto__指向其構(gòu)造函數(shù)的prototype逾礁,將該實例賦值給 Person 的原型,意味著Person的原型 既擁有了 Animal 的所有實例屬性或方法访惜,還包含了一個指向 Animal的原型的指針嘹履。

思考:person.constructor 等于什么腻扇?

示意圖如下:

我們可以再擴(kuò)展代碼:

//省略....
function Student(){
    this.thirdType = "學(xué)生";
}
Student.prototype = new Person();
var student = new Student();
console.log(student.topType+"--"+student.secondType+"--"+student.thirdType);//'脊椎動物--人類--學(xué)生'

在這里增加了第三個構(gòu)造函數(shù)Student,并且將 Person 實例賦給了 Student.prototype砾嫉,這樣幼苛,層級關(guān)系將變?yōu)?Student 繼承了 Person,而 Person 繼承了 Animal焕刮;Student 擁有 Person 和 Animal 的全部共享屬性或方法舶沿,Person 擁有 Animal 的全部共享屬性或方法

擴(kuò)展后的示意圖:

搜索過程?

正如上面的例子配并,在調(diào)用 student.topType 時括荡,是如何得到"脊椎動物"的,在前面的hasOwnProperty知識中荐绝,曾經(jīng)有過涉及一汽,即:

  1. 搜索實例本身
  2. 搜索 Student.prototype
  3. 搜索 Person.prototype
  4. 搜索 Animal.prototype (查找到屬性,返回屬性值)

如下圖:

Object低滩?

在上面的原型鏈圖中,可以看到在尋找某屬性時岩喷,一直找到了 Object.prototype恕沫。所有函數(shù)的默認(rèn)原型都是 Object 的實例,因此默認(rèn)原型都會包含一個指針指向 Object.prototype纱意。而這也是對象或函數(shù)能夠使用toString()方法的原因

更完善的原型鏈?zhǔn)疽鈭D:

原型鏈?zhǔn)嚼^承所帶來的問題婶溯?

  1. 引用數(shù)據(jù)類型問題

    JS面向?qū)ο?/strong>一節(jié)中,我們曾經(jīng)嘗試將引用數(shù)據(jù)類型賦值給原型的屬性(參見<u>創(chuàng)建對象</u>一節(jié)的<u>原型模式</u>)偷霉,結(jié)果出現(xiàn)實例間相互影響迄委,在原型繼承時,也會出現(xiàn)此問題类少,觀察下例:

    function Person(){
      this.desc = ["北京"];
    }
    function Student(){}
    Student.prototype = new Person();
    var s1 = new Student();
    var s2 = new Student();
    s1.desc.push("昌平");
    console.log(s1.desc);//[ '北京', '昌平' ]
    console.log(s2.desc);//[ '北京', '昌平' ]
    

    Person 函數(shù)含有一個desc 屬性叙身,則 Person的實例會包含各自的一個 desc 屬性。但此時的 Student 通過原型鏈繼承了 Person硫狞,Student 的 prototype 則變成了 Person 的一個實例信轿,則 Student 就擁有了一個 desc 屬性,相當(dāng)于使用 Student.prototype.desc=[…]為 Student 添加了這樣一個原型屬性残吩,結(jié)果顯而易見财忽。

  2. 傳參問題

    通過前面的代碼,會發(fā)現(xiàn)泣侮,在使用原型鏈繼承時即彪,無法向父級構(gòu)造函數(shù)傳遞參數(shù)

借用構(gòu)造函數(shù)式繼承

通過使用 call 或 apply 來實現(xiàn)借用式繼承

call 或 apply :更改函數(shù)執(zhí)行的上下文環(huán)境(call 和 apply 的用法在后面的課程中會有講解)

function Person(name){
  this.name = name;
}
function Student(name){
  Person.call(this,name);
}
var student = new Student("zhar");
console.log(student.name);//zhar

上面的代碼中,使用了 call活尊,在 Student 的實例環(huán)境中調(diào)用了 Person 構(gòu)造函數(shù)隶校,更改了 Person 的 this 指向為當(dāng)前實例環(huán)境琼蚯,最終 Student的實例就擁有了 name 屬性

優(yōu)勢

可以在調(diào)用構(gòu)造函數(shù)時,向'父級'傳遞參數(shù)惠况,如上例中一樣遭庶,在調(diào)用 Person 時傳入了 name 值

缺點

無法繼承原型屬性或方法

function Person(name){
  this.name = name;
}
Person.prototype.say = function(){
  console.log(this.name);
}
function Student(name){
  Person.call(this,name);
}
var student = new Student("zhar");
console.log(student.name);//zhar
student.say();//報錯  student.say is not a function

組合繼承

將原型鏈?zhǔn)嚼^承與借用構(gòu)造函數(shù)式繼承組合在一起,結(jié)合二者的優(yōu)勢稠屠。通過原型鏈實現(xiàn)對原型屬性或方法的繼承峦睡,通過借用構(gòu)造函數(shù)實現(xiàn)對實例屬性的繼承

function Person(name){
  this.name = name;
}
Person.prototype.say = function(){
  console.log(this.name);
}
function Student(name){
  Person.call(this,name);
}
Student.prototype = new Person();
var student = new Student("zhar");
console.log(student.name);//zhar
student.say();//zhar
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市权埠,隨后出現(xiàn)的幾起案子榨了,更是在濱河造成了極大的恐慌,老刑警劉巖攘蔽,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件龙屉,死亡現(xiàn)場離奇詭異,居然都是意外死亡满俗,警方通過查閱死者的電腦和手機(jī)转捕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來唆垃,“玉大人五芝,你說我怎么就攤上這事≡颍” “怎么了枢步?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長渐尿。 經(jīng)常有香客問我醉途,道長,這世上最難降的妖魔是什么砖茸? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任隘擎,我火速辦了婚禮,結(jié)果婚禮上渔彰,老公的妹妹穿的比我還像新娘嵌屎。我一直安慰自己,他們只是感情好恍涂,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布宝惰。 她就那樣靜靜地躺著,像睡著了一般再沧。 火紅的嫁衣襯著肌膚如雪尼夺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機(jī)與錄音淤堵,去河邊找鬼寝衫。 笑死,一個胖子當(dāng)著我的面吹牛拐邪,可吹牛的內(nèi)容都是我干的慰毅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼扎阶,長吁一口氣:“原來是場噩夢啊……” “哼汹胃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起东臀,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤着饥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后惰赋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宰掉,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年赁濒,在試婚紗的時候發(fā)現(xiàn)自己被綠了轨奄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡流部,死狀恐怖戚绕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情枝冀,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布耘子,位于F島的核電站果漾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏谷誓。R本人自食惡果不足惜绒障,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捍歪。 院中可真熱鬧户辱,春花似錦、人聲如沸糙臼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽变逃。三九已至必逆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背名眉。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工粟矿, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人损拢。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓陌粹,卻偏偏與公主長得像,于是被迫代替她去往敵國和親福压。 傳聞我的和親對象是個殘疾皇子掏秩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355

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