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

歡迎訪問 生活随笔!

生活随笔

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

javascript

JavaScript | 继承

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

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

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

原型鏈

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

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

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

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

    instance SubType.prototype SuperType.prototype Object.prototype

  • p.s.

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

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

  • 缺點:

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

    在創建子類型的實例時,不能向超類型的構造函數中傳遞參數。

// "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的實例調用getSuperValue時調用的就是這個重新定義的方法,但通過SuperType的實例調用時還會繼續調用原來的方法 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 // 確認原型和實例的關系 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"]

?

借用構造函數(偽造對象 / 經典繼承)

  • 在子類型構造函數的內部調用超類型構造函數
  • 優點:

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

    可以在子類型構造函數中向超類型構造函數傳遞參數

  • 缺點:

    無法避免構造函數模式存在的問題:方法都在構造函數中定義,無法實現函數復用

// "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"]

?

組合繼承(偽經典繼承)

  • 將原型鏈和借用構造函數組合,使用原型鏈實現對原型屬性和方法的繼承,通過借用構造函數來實現對實例屬性的繼承
  • 對應創建對象 <組合使用構造函數模式和原型模式>
  • 優點:最常用
  • 缺點:需要調用兩次超類型構造函數,一次在創建子函數原型時,另一次在子函數構造函數內部。調用子類型構造函數時需要重寫屬性
// "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

?

原型式繼承

  • 對應創建對象 <動態原型模式>
  • 沒有使用嚴格意義上的構造函數,借助已有的對象創建新對象
  • 優點:

    在不想創建構造函數,只想讓一個對象與另一個對象保持類似的情況下,原型式繼承完全可以勝任

  • 缺點:

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

// "use strict"; function object(o){function F(){} // 創建臨時性構造函數F.prototype = o; // 將傳入的對象作為構造函數的原型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()規范化原型式繼承 // 以這種方式指定的任何屬性都會覆蓋原型對象上的同名屬性 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);

?

寄生式繼承

  • 對應創建對象 <寄生構造函數 / 工廠模式>
  • 創建一個僅用于封裝繼承過程的函數,在內部增強對象,最后返回對象
  • 示范集成模式時使用的object()函數不是必須的,任何能夠返回新對象的函數都適用于此模式
  • 使用場景:在主要考慮對象而不是自定義類型和構造函數的情況下,寄生式繼承也是一種有用的模式
  • 缺點:無法做到函數復用,類似于構造函數模式
// "use strict"; function object(o) {function F() {} // 創建臨時性構造函數F.prototype = o; // 將傳入的對象作為構造函數的原型return new F(); // 返回臨時類型的一個新實例 }function createAnother(original) { // 接收的函數作為新對象基礎的對象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);

?

寄生組合式繼承

  • 優點:

    最理想的繼承范式

    解決組合繼承重寫屬性的問題,只調用了一次SuperType構造函數

    避免了在SubType.prototype上創建不必要的屬性

    原型鏈保持不變

    能夠正常使用instanceofisPrototypeOf()

"use strict"; function object(o) {function F() {}F.prototype = o;return new F(); }// 1.創建超類型原型的一個副本 // 2.為創建的副本添加constructor屬性,彌補因重寫原型而失去的屬性 // 3.將新創建的對象(即副本)賦值給子類型的原型 function inheritProtoType(subType,superType){var prototype = object(superType.prototype); // 創建對象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); }

轉載于:https://www.cnblogs.com/hughdong/p/7264122.html

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。