日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

JavaScript | 继承

發(fā)布時間:2024/10/12 javascript 91 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JavaScript | 继承 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

—————————————————————————————————————————————————————————

繼承 - ECMAScript只支持實現(xiàn)繼承(依靠原型鏈),不支持接口繼承(函數(shù)沒有簽名)

原型鏈

  • 利用原型讓一個引用類型繼承另一個引用類型的屬性和方法,
  • 構(gòu)造函數(shù)、原型、實例的關(guān)系:每個構(gòu)造函數(shù)都有一個原型對象,原型對象包含一個指向構(gòu)造函數(shù)的指針。實例包含一個指向原型對象的內(nèi)部指針,在創(chuàng)建實例之后即指向原型對象
  • 而當A原型對象的指針指向B個原型對象時(此時A原型對象與B實例同級),就形成了一條原型鏈。
  • 圖解:

    原型搜索機制:當讀取模式訪問一個實例屬性時,首先會在實例中搜索該屬性,如果沒有找到該屬性則沿著原型鏈向上查找

    在例子<Demo-1>中,調(diào)用instance.getSuperValue(),先搜索實例instance,再搜索SubType.prototype,再搜索SuperType.protorype,最后一步才找到該方法。

    默認的原型:所有的引用類型默認都繼承了Object,所以默認原型的指針都會指向Object.prototype,完整的原型鏈如下:

    instance SubType.prototype SuperType.prototype Object.prototype

  • p.s.

    必須替換掉實例的原型后才能給實例添加方法

    不能使用對象字面量創(chuàng)建原型方法,這樣做會重寫原型鏈,如<Demo-3>

  • 缺點:

    包含引用類型值(Function Object Array)的原型屬性會被所有實例共享,在通過原型來實現(xiàn)繼承時,原型實際上會變成另一個類型的實例,所以原先的實例屬性就變成了現(xiàn)在的原型屬性了。<Demo-4>

    在創(chuàng)建子類型的實例時,不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)。

// "use strict";// Demo - 1 // SuperType 擁有一個屬性和一個方法 // SubType 擁有一個屬性和一個方法,又從SuperType那里繼承了一個屬性一個方法 function SuperType(){this.property = "111"; } SuperType.prototype.getSuperValue = function(){return this.property; } function SubType(){this.subproperty = "222"; } // p.s.new操作之前,SubType.prototype指向的是function,不允許為function()定義.getSubValue方法,所以要將添加方法放在修改原型指向之后 // 操作之后SubType.prototype指向SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function(){ // 必須在SubType替換原型之后才能定義return this.subproperty; } var instance = new SubType(); console.log(instance.property); // 111 console.log(instance.getSuperValue()); // 111 console.log(instance.subproperty); // 222 console.log(instance.getSubValue()); // 222 console.log(instance.constructor); // f SuperType(){} 原本SubType中的constructor屬性被重寫 // 重寫SuperType.getSuperValue() // 如果要重寫這個方法,會屏蔽原來的方法 // 換句話說,當通過SubType的實例調(diào)用getSuperValue時調(diào)用的就是這個重新定義的方法,但通過SuperType的實例調(diào)用時還會繼續(xù)調(diào)用原來的方法 var beforeReWrite = new SuperType(); SuperType.prototype.getSuperValue = function(){console.log("rewrite"); } console.log(instance.getSuperValue()); // rewrite,this.property = undefined console.log(SuperType.prototype.getSuperValue()); // rewrite,this.property = undefined console.log(beforeReWrite.getSuperValue());// Demo - 2 // 確認原型和實例的關(guān)系 console.log(instance instanceof Object); // true console.log(instance instanceof SuperType); // true console.log(instance instanceof SubType); // true // 另一種方法 console.log(Object.prototype.isPrototypeOf(instance)); // true console.log(SuperType.prototype.isPrototypeOf(instance)); // true console.log(SubType.prototype.isPrototypeOf(instance)); // true// Demo - 3 function SuperType2(){this.property = "1111"; } SuperType2.prototype.getSuperValue = function(){return this.property; } function SubType2(){this.subproperty = "2222"; } SubType2.prototype = new SuperType2(); SubType2.prototype = {getSubValue:function(){return this.subproperty;},someOtherMethod:function(){return false;} } var instance2 = new SubType2(); console.log(instance2 instanceof Object); // true console.log(instance2 instanceof SuperType2); // false,原型鏈被切斷 console.log(instance2 instanceof SubType2); // true // console.log(instance2.getSuperValue()); // error// Demo - 4 function SuperType3(){this.colors = ["red","blue","green"]; } function SubType3(){} SubType3.prototype = new SuperType3(); var instance3 = new SubType3(); instance3.colors.push("black"); console.log(instance3.colors); // ["red", "blue", "green", "black"] var instance4 = new SubType3(); console.log(instance4.colors); // ["red", "blue", "green", "black"]

?

借用構(gòu)造函數(shù)(偽造對象 / 經(jīng)典繼承)

  • 在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)
  • 優(yōu)點:

    解決了單獨使用原型鏈共享引用類型值屬性的問題

    可以在子類型構(gòu)造函數(shù)中向超類型構(gòu)造函數(shù)傳遞參數(shù)

  • 缺點:

    無法避免構(gòu)造函數(shù)模式存在的問題:方法都在構(gòu)造函數(shù)中定義,無法實現(xiàn)函數(shù)復(fù)用

// "use strict";function SuperType(name) {this.name = name;this.colors = ["111", "222", "333"]; }function SubType() {SuperType.call(this, "name1");this.age = 20; }var instance = new SubType(); instance.colors.push("444"); console.log(instance.colors); // ["111", "222", "333", "444"] console.log(instance.name); // name1 console.log(instance.age); // 20 var instance2 = new SubType(); console.log(instance2.colors); // ["111", "222", "333"]

?

組合繼承(偽經(jīng)典繼承)

  • 將原型鏈和借用構(gòu)造函數(shù)組合,使用原型鏈實現(xiàn)對原型屬性和方法的繼承,通過借用構(gòu)造函數(shù)來實現(xiàn)對實例屬性的繼承
  • 對應(yīng)創(chuàng)建對象 <組合使用構(gòu)造函數(shù)模式和原型模式>
  • 優(yōu)點:最常用
  • 缺點:需要調(diào)用兩次超類型構(gòu)造函數(shù),一次在創(chuàng)建子函數(shù)原型時,另一次在子函數(shù)構(gòu)造函數(shù)內(nèi)部。調(diào)用子類型構(gòu)造函數(shù)時需要重寫屬性
// "use strict"; function SuperType(name) {this.name = name;this.colors = ["111", "222", "333"]; } SuperType.prototype.sayName = function() {console.log(this.name); }function SubType(name, age) {SuperType.call(this, name); // 繼承屬性this.age = age; } SubType.prototype = new SuperType(); // 繼承方法 SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function() {console.log(this.age); } var instance1 = new SubType("hugh", 20); instance1.colors.push("444"); console.log(instance1.colors); // ["111", "222", "333", "444"] instance1.sayName(); // hugh instance1.sayAge(); // 20 var instance2 = new SubType("dong", 21); console.log(instance2.colors); // ["111", "222", "333"] instance2.sayName(); // dong instance2.sayAge(); // 21

?

原型式繼承

  • 對應(yīng)創(chuàng)建對象 <動態(tài)原型模式>
  • 沒有使用嚴格意義上的構(gòu)造函數(shù),借助已有的對象創(chuàng)建新對象
  • 優(yōu)點:

    在不想創(chuàng)建構(gòu)造函數(shù),只想讓一個對象與另一個對象保持類似的情況下,原型式繼承完全可以勝任

  • 缺點:

    包含引用類型值的屬性始終都會共享,就像原型模式一樣

// "use strict"; function object(o){function F(){} // 創(chuàng)建臨時性構(gòu)造函數(shù)F.prototype = o; // 將傳入的對象作為構(gòu)造函數(shù)的原型return new F(); // 返回臨時類型的一個新實例 }var person = {name:"hugh",friends:["111",'222','333'] };var anotherPerson = object(person); anotherPerson.name = "dong"; anotherPerson.friends.push("444");var yetAnotherPerson = object(person); yetAnotherPerson.name = "hehe"; yetAnotherPerson.friends.push("555");console.log(person.friends); // ["111", "222", "333", "444", "555"] console.log(person.name); // hugh console.log(anotherPerson.friends); // ["111", "222", "333", "444", "555"] console.log(anotherPerson.name); // dong console.log(yetAnotherPerson.friends); // ["111", "222", "333", "444", "555"] console.log(yetAnotherPerson.name); // hehe// 使用Object.create()規(guī)范化原型式繼承 // 以這種方式指定的任何屬性都會覆蓋原型對象上的同名屬性 var otherPerson1 = Object.create(person); otherPerson1.friends.push("666"); console.log(yetAnotherPerson.friends); // ["111", "222", "333", "444", "555", "666"] var otherPerson2 = Object.create(person,{name:{value:"test"} }); console.log(otherPerson2.name);

?

寄生式繼承

  • 對應(yīng)創(chuàng)建對象 <寄生構(gòu)造函數(shù) / 工廠模式>
  • 創(chuàng)建一個僅用于封裝繼承過程的函數(shù),在內(nèi)部增強對象,最后返回對象
  • 示范集成模式時使用的object()函數(shù)不是必須的,任何能夠返回新對象的函數(shù)都適用于此模式
  • 使用場景:在主要考慮對象而不是自定義類型和構(gòu)造函數(shù)的情況下,寄生式繼承也是一種有用的模式
  • 缺點:無法做到函數(shù)復(fù)用,類似于構(gòu)造函數(shù)模式
// "use strict"; function object(o) {function F() {} // 創(chuàng)建臨時性構(gòu)造函數(shù)F.prototype = o; // 將傳入的對象作為構(gòu)造函數(shù)的原型return new F(); // 返回臨時類型的一個新實例 }function createAnother(original) { // 接收的函數(shù)作為新對象基礎(chǔ)的對象var clone = object(original);clone.sayHi = function() { // 添加新方法console.log('hi');};return clone; } var person = {name: "hugh",friends: ['111', '222', '333'] }; var person1 = createAnother(person); person1.sayHi(); console.log(person1.name); console.log(person1.friends);

?

寄生組合式繼承

  • 優(yōu)點:

    最理想的繼承范式

    解決組合繼承重寫屬性的問題,只調(diào)用了一次SuperType構(gòu)造函數(shù)

    避免了在SubType.prototype上創(chuàng)建不必要的屬性

    原型鏈保持不變

    能夠正常使用instanceofisPrototypeOf()

"use strict"; function object(o) {function F() {}F.prototype = o;return new F(); }// 1.創(chuàng)建超類型原型的一個副本 // 2.為創(chuàng)建的副本添加constructor屬性,彌補因重寫原型而失去的屬性 // 3.將新創(chuàng)建的對象(即副本)賦值給子類型的原型 function inheritProtoType(subType,superType){var prototype = object(superType.prototype); // 創(chuàng)建對象prototype.constructor = subType; // 增強對象subType.prototype = prototype; // 指定對象 } function SuperType(name){this.name = name;this.colors= [1,2,3,4]; } SuperType.prototype.sayName = function(){console.log(this.name); } function SubType(name,age){SuperType.call(this,name);this.age = age; } inheritProtoType(SubType,SuperType); SubType.prototype.sayAge = function(){console.log(this.age); }

轉(zhuǎn)載于:https://www.cnblogs.com/hughdong/p/7264122.html

總結(jié)

以上是生活随笔為你收集整理的JavaScript | 继承的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。