原型、原型鏈篡诽、及拓展(ES5的繼承模式)

原型

  1. 概念:
  • 原型就是一個對象
  • 每個函數(shù)都有一個prototype的屬性崖飘,該屬性指向的是當(dāng)前函數(shù)的顯示原型對象
  • 每個實例對象都有一個____proto____屬性,該屬性指向當(dāng)前實例對象的隱式原型對象
  • 構(gòu)造函數(shù)的顯示原型對象 === 當(dāng)前構(gòu)造函數(shù)的實例對象的隱式原型對象
let Person = function() {};
// 1. 每個函數(shù)都偶有一個屬性prototype
console.log(Person.prototype); // 空對象 ------> 原型對象(隱式原型對象)
let person1 = new Person(); // 生成實例對象
// 2. 每個實例對象身上都有一個屬性__proto__杈女,該屬性指向當(dāng)前實例對象的原型對象(隱形原型對象)
// 3. 構(gòu)造函數(shù)的顯示原型對象 === 當(dāng)前構(gòu)造函數(shù)實例對象的隱式原型對象
Person.prototype === person1.__proto__; // true
  1. 對象:
  • 實例對象(只可用「對象.屬性」調(diào)用)
  • 函數(shù)對象(可用「對象.屬性」調(diào)用朱浴,也可用「對象()」的方式調(diào)用)

原型鏈

  • 當(dāng)使用 「對象.屬性」 的時候,先從自身去查找有無該屬性达椰。如果沒有翰蠢,會沿著____proto____原型鏈去找,直到找到Object(Object是一個函數(shù)對象)的原型對象啰劲,如果還沒有則返回undefined梁沧。
  • ____proto____這條鏈就是原型鏈。
a.b
// 找a會沿著 作用域 找蝇裤,找b(對象的屬性)會沿著原型鏈找

原型鏈圖解.png


原型拓展

拓展一:instanceof運算符

instanceof是如何判斷的?

  • 表達式:A instanceof B
  • 如何B函數(shù)的顯示原型對象在A對象的原型鏈上廷支,返回true,否則返回false
let Person = function() {}; // 構(gòu)造函數(shù)
let person1 = new Person(); // 創(chuàng)建實例對象

person1 instanceof Person; // true (person1.__proto__ === Person.prototype)
person1 instanceof Object; // true (Person.__proto__.__proto__ === Object.prototype)


person1 instanceof Function; // false
Person instanceof Function; // true

手動封裝一個 instanceof

function myInstanceof(left, right) {
  // 獲取對象的原型
  let proto = Object.getPrototypeOf(left)
  // 獲取構(gòu)造函數(shù)的 prototype 對象
  let prototype = right.prototype; 
 
  // 判斷構(gòu)造函數(shù)的 prototype 對象是否在對象的原型鏈上
  while (true) {
    if (!proto) return false;
    if (proto === prototype) return true;
    // 如果沒有找到恋拍,就繼續(xù)從其原型上找,Object.getPrototypeOf方法用來獲取指定對象的原型
    proto = Object.getPrototypeOf(proto);
  }
}


拓展二:Object.getPropertyNames() 藕甩、Object.keys()for..in

區(qū)別

由上圖可見芝囤,for..in可以遍歷對象上所有的屬性,包括原型屬性;而
Object.getPropertyNames()Object.keys()只能遍歷對象中可枚舉的屬性悯姊。

另羡藐,obj.hasOwnProperty(propName)方法會返回一個布爾值,指示對象自身屬性中是否具有指定的屬性(也就是悯许,是否有指定的鍵)仆嗦,不包括原型鏈上的屬性。故先壕,一般與for..in配合使用瘩扼。

for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
            // 處理自身屬性    
      }
    }


拓展三:ES5的繼承模式

1. 原型鏈繼承
// 父類
function Animal(name, age) {
    this.name = name;
    this.age = age;
    this.attrObj = {
        type: 'animal'
    };
}
Animal.prototype.eat = function() {
    console.log(this.name + '在吃東西');
}

// 子類
function Cat(name, age) {
    this.name = name;
    this.age = age;
}
Cat.prototype = new Animal(); // 讓子類的原型 成為 父類的實例對象

let tom = new Cat('tom', 3);
tom.eat(); // tom在吃東西
tom的原型鏈
  • 缺點
    i) 無法向父類的構(gòu)造方法傳參
    ii) 所有Cat的實例對象的原型鏈都會指向同一個Animal實例, 因此對某個Cat實例的來自父類的引用類型變量修改會影響所有的Cat實例
let momo = new Cat('momo', 3);
momo.attrObj.type = '波斯貓';

let kate = new Cat('kate', 2);
kate.attrObj.type // 波斯貓


2. 構(gòu)造函數(shù)繼承
// 父類
function Animal(name, age) {
    this.name = name;
    this.age = age;
}
Animal.prototype.eat = function() {
    console.log(this.name + '在吃東西');
}

function Cat(name, age, sex) {
    this.sex = sex;
    Animal.call(this, name, age);  // 利用call改變this指向
}
let tom = new Cat('tom', 3, 'boy');
tom當(dāng)前原型鏈
  • 缺點
    繼承不到父類原型上的屬性和方法
3. 組合繼承
// 父類
function Animal(name, age) {
    this.name = name;
    this.age = age;
}
Animal.prototype.eat = function() {
    console.log(this.name + '在吃東西');
}

// 子類
function Cat(name, age, sex) {
    this.sex = sex;
    Animal.call(this, name, age);  // 利用call改變this指向
}
Cat.prototype = new Animal(); // 讓子類的原型 成為 父類的實例對象

let tom = new Cat('tom', 3, 'boy');
tom.eat(); // tom在吃東西
tom當(dāng)前的原型鏈
  • 缺點
    每次創(chuàng)建子類實例都執(zhí)行了兩次構(gòu)造函數(shù)(Animal.call和 new Animal()),雖然這并不影響對父類的繼承垃僚,但子類創(chuàng)建實例時集绰,原型中會存在兩份相同的屬性和方法,這并不優(yōu)雅谆棺。


4. 寄生式組合繼承

解決構(gòu)造函數(shù)被執(zhí)行兩次的問題, 我們將指向父類實例改為指向父類原型, 減去一次構(gòu)造函數(shù)的執(zhí)行栽燕。

  • Object.create() 方法用于創(chuàng)建一個新對象,使用現(xiàn)有的對象來作為新創(chuàng)建對象的原型(prototype)
// 父類
function Animal(name, age) {
    this.name = name;
    this.age = age;
    this.attrObj = {
        type: 'animal'
    };
}
Animal.prototype.eat = function() {
    console.log(this.name + '在吃東西');
}
// 子類
function Cat(name, age, sex) {
    this.sex = sex;
    Animal.call(this, name, age);  // 利用call改變this指向
}

// 與組合式繼承的區(qū)別在于將Cat.prototype = new Animal(); 替換成 Cat.prototype = Object.create(Animal.prototype);
// Cat.prototype = Object.create(Animal.prototype)的意義為: Cat.prototype.__proto__ === Animal.prototype
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;

let tom = new Cat('tom', 3, 'boy');
tom.eat(); // tom在吃東西
tom.attrObj.type = '波斯貓';

let kate = new Cat('kate', 2, 'girl');
console.log('kate.attrObj.type: ', kate.attrObj.type); // animal
new關(guān)鍵字創(chuàng)建的對象與Object.create(proto, propertiesObject)的區(qū)別
  • new Object()生成的對象會繼承原型上的方法和屬性并且會繼承構(gòu)造函數(shù)的本地的屬性改淑。
  • Object.create(proto, propertiesObject)只會繼承原型鏈上的方法和屬性(參數(shù)proto:是新創(chuàng)建對象的原型對象碍岔,必填。)
let Person = function() {};
let p1 = new Person(); // 生成實例對象
p1.__proto__ === Person.prototype; // true

// 當(dāng)我們不希望執(zhí)行構(gòu)造函數(shù)朵夏,而只需要繼承父類的原型上的方法和屬性時
let p2 = Object.create(Person.prototype);
p2.__proto__ === Person.prototype; // true
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蔼啦,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子仰猖,更是在濱河造成了極大的恐慌捏肢,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饥侵,死亡現(xiàn)場離奇詭異猛计,居然都是意外死亡,警方通過查閱死者的電腦和手機爆捞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門奉瘤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人煮甥,你說我怎么就攤上這事盗温。” “怎么了成肘?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵卖局,是天一觀的道長。 經(jīng)常有香客問我双霍,道長砚偶,這世上最難降的妖魔是什么批销? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮染坯,結(jié)果婚禮上均芽,老公的妹妹穿的比我還像新娘。我一直安慰自己单鹿,他們只是感情好掀宋,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著仲锄,像睡著了一般劲妙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上儒喊,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天镣奋,我揣著相機與錄音,去河邊找鬼怀愧。 笑死侨颈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掸驱。 我是一名探鬼主播肛搬,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼没佑,長吁一口氣:“原來是場噩夢啊……” “哼毕贼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蛤奢,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤鬼癣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后啤贩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體待秃,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年痹屹,在試婚紗的時候發(fā)現(xiàn)自己被綠了章郁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡志衍,死狀恐怖暖庄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情楼肪,我是刑警寧澤培廓,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站春叫,受9級特大地震影響肩钠,放射性物質(zhì)發(fā)生泄漏泣港。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一价匠、第九天 我趴在偏房一處隱蔽的房頂上張望当纱。 院中可真熱鬧,春花似錦霞怀、人聲如沸惫东。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽廉沮。三九已至,卻和暖如春徐矩,著一層夾襖步出監(jiān)牢的瞬間滞时,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工滤灯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坪稽,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓鳞骤,卻偏偏與公主長得像窒百,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子豫尽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

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