成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

JavaScript常用八種繼承方案

wpw / 773人閱讀

摘要:原型式繼承利用一個(gè)空對(duì)象作為中介,將某個(gè)對(duì)象直接賦值給空對(duì)象構(gòu)造函數(shù)的原型。其中表示構(gòu)造函數(shù),一個(gè)類(lèi)中只能有一個(gè)構(gòu)造函數(shù),有多個(gè)會(huì)報(bào)出錯(cuò)誤如果沒(méi)有顯式指定構(gòu)造方法,則會(huì)添加默認(rèn)的方法,使用例子如下。

(關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo))

更新:在常用七種繼承方案的基礎(chǔ)之上增加了ES6的類(lèi)繼承,所以現(xiàn)在變成八種啦,歡迎加高級(jí)前端進(jìn)階群一起學(xué)習(xí)(文末)。

--- 2018.10.30

1、原型鏈繼承

構(gòu)造函數(shù)、原型和實(shí)例之間的關(guān)系:每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個(gè)原型對(duì)象的指針。

繼承的本質(zhì)就是復(fù)制,即重寫(xiě)原型對(duì)象,代之以一個(gè)新類(lèi)型的實(shí)例。

function SuperType() {
    this.property = true;
}

SuperType.prototype.getSuperValue = function() {
    return this.property;
}

function SubType() {
    this.subproperty = false;
}

// 這里是關(guān)鍵,創(chuàng)建SuperType的實(shí)例,并將該實(shí)例賦值給SubType.prototype
SubType.prototype = new SuperType(); 

SubType.prototype.getSubValue = function() {
    return this.subproperty;
}

var instance = new SubType();
console.log(instance.getSuperValue()); // true

原型鏈方案存在的缺點(diǎn):多個(gè)實(shí)例對(duì)引用類(lèi)型的操作會(huì)被篡改。

function SuperType(){
  this.colors = ["red", "blue", "green"];
}
function SubType(){}

SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"

var instance2 = new SubType(); 
alert(instance2.colors); //"red,blue,green,black"
2、借用構(gòu)造函數(shù)繼承

使用父類(lèi)的構(gòu)造函數(shù)來(lái)增強(qiáng)子類(lèi)實(shí)例,等同于復(fù)制父類(lèi)的實(shí)例給子類(lèi)(不使用原型)

function  SuperType(){
    this.color=["red","green","blue"];
}
function  SubType(){
    //繼承自SuperType
    SuperType.call(this);
}
var instance1 = new SubType();
instance1.color.push("black");
alert(instance1.color);//"red,green,blue,black"

var instance2 = new SubType();
alert(instance2.color);//"red,green,blue"

核心代碼是SuperType.call(this),創(chuàng)建子類(lèi)實(shí)例時(shí)調(diào)用SuperType構(gòu)造函數(shù),于是SubType的每個(gè)實(shí)例都會(huì)將SuperType中的屬性復(fù)制一份。

缺點(diǎn):

只能繼承父類(lèi)的實(shí)例屬性和方法,不能繼承原型屬性/方法

無(wú)法實(shí)現(xiàn)復(fù)用,每個(gè)子類(lèi)都有父類(lèi)實(shí)例函數(shù)的副本,影響性能

3、組合繼承

組合上述兩種方法就是組合繼承。用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,用借用構(gòu)造函數(shù)技術(shù)來(lái)實(shí)現(xiàn)實(shí)例屬性的繼承。

function SuperType(name){
  this.name = name;
  this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
  alert(this.name);
};

function SubType(name, age){
  // 繼承屬性
  // 第二次調(diào)用SuperType()
  SuperType.call(this, name);
  this.age = age;
}

// 繼承方法
// 構(gòu)建原型鏈
// 第一次調(diào)用SuperType()
SubType.prototype = new SuperType(); 
// 重寫(xiě)SubType.prototype的constructor屬性,指向自己的構(gòu)造函數(shù)SubType
SubType.prototype.constructor = SubType; 
SubType.prototype.sayAge = function(){
    alert(this.age);
};

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29

var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27

缺點(diǎn):

第一次調(diào)用SuperType():給SubType.prototype寫(xiě)入兩個(gè)屬性name,color。

第二次調(diào)用SuperType():給instance1寫(xiě)入兩個(gè)屬性name,color。

實(shí)例對(duì)象instance1上的兩個(gè)屬性就屏蔽了其原型對(duì)象SubType.prototype的兩個(gè)同名屬性。所以,組合模式的缺點(diǎn)就是在使用子類(lèi)創(chuàng)建實(shí)例對(duì)象時(shí),其原型中會(huì)存在兩份相同的屬性/方法。

4、原型式繼承

利用一個(gè)空對(duì)象作為中介,將某個(gè)對(duì)象直接賦值給空對(duì)象構(gòu)造函數(shù)的原型。

function object(obj){
  function F(){}
  F.prototype = obj;
  return new F();
}

object()對(duì)傳入其中的對(duì)象執(zhí)行了一次淺復(fù)制,將構(gòu)造函數(shù)F的原型直接指向傳入的對(duì)象。

var person = {
  name: "Nicholas",
  friends: ["Shelby", "Court", "Van"]
};

var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"

缺點(diǎn):

原型鏈繼承多個(gè)實(shí)例的引用類(lèi)型屬性指向相同,存在篡改的可能。

無(wú)法傳遞參數(shù)

另外,ES5中存在Object.create()的方法,能夠代替上面的object方法。

5、寄生式繼承

核心:在原型式繼承的基礎(chǔ)上,增強(qiáng)對(duì)象,返回構(gòu)造函數(shù)

function createAnother(original){
  var clone = object(original); // 通過(guò)調(diào)用 object() 函數(shù)創(chuàng)建一個(gè)新對(duì)象
  clone.sayHi = function(){  // 以某種方式來(lái)增強(qiáng)對(duì)象
    alert("hi");
  };
  return clone; // 返回這個(gè)對(duì)象
}

函數(shù)的主要作用是為構(gòu)造函數(shù)新增屬性和方法,以增強(qiáng)函數(shù)

var person = {
  name: "Nicholas",
  friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"

缺點(diǎn)(同原型式繼承):

原型鏈繼承多個(gè)實(shí)例的引用類(lèi)型屬性指向相同,存在篡改的可能。

無(wú)法傳遞參數(shù)

6、寄生組合式繼承

結(jié)合借用構(gòu)造函數(shù)傳遞參數(shù)和寄生模式實(shí)現(xiàn)繼承

function inheritPrototype(subType, superType){
  var prototype = Object.create(superType.prototype); // 創(chuàng)建對(duì)象,創(chuàng)建父類(lèi)原型的一個(gè)副本
  prototype.constructor = subType;                    // 增強(qiáng)對(duì)象,彌補(bǔ)因重寫(xiě)原型而失去的默認(rèn)的constructor 屬性
  subType.prototype = prototype;                      // 指定對(duì)象,將新創(chuàng)建的對(duì)象賦值給子類(lèi)的原型
}

// 父類(lèi)初始化實(shí)例屬性和原型屬性
function SuperType(name){
  this.name = name;
  this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
  alert(this.name);
};

// 借用構(gòu)造函數(shù)傳遞增強(qiáng)子類(lèi)實(shí)例屬性(支持傳參和避免篡改)
function SubType(name, age){
  SuperType.call(this, name);
  this.age = age;
}

// 將父類(lèi)原型指向子類(lèi)
inheritPrototype(SubType, SuperType);

// 新增子類(lèi)原型屬性
SubType.prototype.sayAge = function(){
  alert(this.age);
}

var instance1 = new SubType("xyc", 23);
var instance2 = new SubType("lxy", 23);

instance1.colors.push("2"); // ["red", "blue", "green", "2"]
instance1.colors.push("3"); // ["red", "blue", "green", "3"]

這個(gè)例子的高效率體現(xiàn)在它只調(diào)用了一次SuperType?構(gòu)造函數(shù),并且因此避免了在SubType.prototype?上創(chuàng)建不必要的、多余的屬性。于此同時(shí),原型鏈還能保持不變;因此,還能夠正常使用instanceof?和isPrototypeOf()

這是最成熟的方法,也是現(xiàn)在庫(kù)實(shí)現(xiàn)的方法

7、混入方式繼承多個(gè)對(duì)象
function MyClass() {
     SuperClass.call(this);
     OtherSuperClass.call(this);
}

// 繼承一個(gè)類(lèi)
MyClass.prototype = Object.create(SuperClass.prototype);
// 混合其它
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// 重新指定constructor
MyClass.prototype.constructor = MyClass;

MyClass.prototype.myMethod = function() {
     // do something
};

Object.assign會(huì)把 OtherSuperClass原型上的函數(shù)拷貝到 MyClass原型上,使 MyClass 的所有實(shí)例都可用 OtherSuperClass 的方法。

8、ES6類(lèi)繼承extends

extends關(guān)鍵字主要用于類(lèi)聲明或者類(lèi)表達(dá)式中,以創(chuàng)建一個(gè)類(lèi),該類(lèi)是另一個(gè)類(lèi)的子類(lèi)。其中constructor表示構(gòu)造函數(shù),一個(gè)類(lèi)中只能有一個(gè)構(gòu)造函數(shù),有多個(gè)會(huì)報(bào)出SyntaxError錯(cuò)誤,如果沒(méi)有顯式指定構(gòu)造方法,則會(huì)添加默認(rèn)的 constructor方法,使用例子如下。

class Rectangle {
    // constructor
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
    
    // Getter
    get area() {
        return this.calcArea()
    }
    
    // Method
    calcArea() {
        return this.height * this.width;
    }
}

const rectangle = new Rectangle(10, 20);
console.log(rectangle.area);
// 輸出 200

-----------------------------------------------------------------
// 繼承
class Square extends Rectangle {

  constructor(length) {
    super(length, length);
    
    // 如果子類(lèi)中存在構(gòu)造函數(shù),則需要在使用“this”之前首先調(diào)用 super()。
    this.name = "Square";
  }

  get area() {
    return this.height * this.width;
  }
}

const square = new Square(10);
console.log(square.area);
// 輸出 100

extends繼承的核心代碼如下,其實(shí)現(xiàn)和上述的寄生組合式繼承方式一樣

function _inherits(subType, superType) {
  
    // 創(chuàng)建對(duì)象,創(chuàng)建父類(lèi)原型的一個(gè)副本
    // 增強(qiáng)對(duì)象,彌補(bǔ)因重寫(xiě)原型而失去的默認(rèn)的constructor 屬性
    // 指定對(duì)象,將新創(chuàng)建的對(duì)象賦值給子類(lèi)的原型
    subType.prototype = Object.create(superType && superType.prototype, {
        constructor: {
            value: subType,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    
    if (superType) {
        Object.setPrototypeOf 
            ? Object.setPrototypeOf(subType, superType) 
            : subType.__proto__ = superType;
    }
}
總結(jié)

1、函數(shù)聲明和類(lèi)聲明的區(qū)別

函數(shù)聲明會(huì)提升,類(lèi)聲明不會(huì)。首先需要聲明你的類(lèi),然后訪(fǎng)問(wèn)它,否則像下面的代碼會(huì)拋出一個(gè)ReferenceError。

let p = new Rectangle(); 
// ReferenceError

class Rectangle {}

2、ES5繼承和ES6繼承的區(qū)別

ES5的繼承實(shí)質(zhì)上是先創(chuàng)建子類(lèi)的實(shí)例對(duì)象,然后再將父類(lèi)的方法添加到this上(Parent.call(this)).

ES6的繼承有所不同,實(shí)質(zhì)上是先創(chuàng)建父類(lèi)的實(shí)例對(duì)象this,然后再用子類(lèi)的構(gòu)造函數(shù)修改this。因?yàn)樽宇?lèi)沒(méi)有自己的this對(duì)象,所以必須先調(diào)用父類(lèi)的super()方法,否則新建實(shí)例報(bào)錯(cuò)。

《javascript高級(jí)程序設(shè)計(jì)》筆記:繼承  
MDN之Object.create()
MDN之Class
交流

本人Github鏈接如下,歡迎各位Star

http://github.com/yygmind/blog

我是木易楊,網(wǎng)易高級(jí)前端工程師,跟著我每周重點(diǎn)攻克一個(gè)前端面試重難點(diǎn)。接下來(lái)讓我?guī)阕哌M(jìn)高級(jí)前端的世界,在進(jìn)階的路上,共勉!

如果你想加群討論每期面試知識(shí)點(diǎn),公眾號(hào)回復(fù)[加群]即可

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/98946.html

相關(guān)文章

  • 【進(jìn)階3-3期】深度解析 call 和 apply 原理、使用場(chǎng)景及實(shí)現(xiàn)

    摘要:之前文章詳細(xì)介紹了的使用,不了解的查看進(jìn)階期。不同的引擎有不同的限制,核心限制在,有些引擎會(huì)拋出異常,有些不拋出異常但丟失多余參數(shù)。存儲(chǔ)的對(duì)象能動(dòng)態(tài)增多和減少,并且可以存儲(chǔ)任何值。這邊采用方法來(lái)實(shí)現(xiàn),拼成一個(gè)函數(shù)。 之前文章詳細(xì)介紹了 this 的使用,不了解的查看【進(jìn)階3-1期】。 call() 和 apply() call() 方法調(diào)用一個(gè)函數(shù), 其具有一個(gè)指定的 this 值和分...

    godlong_X 評(píng)論0 收藏0
  • 【進(jìn)階3-5期】深度解析 new 原理及模擬實(shí)現(xiàn)

    摘要:使用指定的參數(shù)調(diào)用構(gòu)造函數(shù),并將綁定到新創(chuàng)建的對(duì)象。由構(gòu)造函數(shù)返回的對(duì)象就是表達(dá)式的結(jié)果。情況返回以外的基本類(lèi)型實(shí)例中只能訪(fǎng)問(wèn)到構(gòu)造函數(shù)中的屬性,和情況完全相反,結(jié)果相當(dāng)于沒(méi)有返回值。 定義 new 運(yùn)算符創(chuàng)建一個(gè)用戶(hù)定義的對(duì)象類(lèi)型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象的實(shí)例。 ——(來(lái)自于MDN) 舉個(gè)栗子 function Car(color) { this.color = co...

    Baaaan 評(píng)論0 收藏0
  • Java 總結(jié)

    摘要:中的詳解必修個(gè)多線(xiàn)程問(wèn)題總結(jié)個(gè)多線(xiàn)程問(wèn)題總結(jié)有哪些源代碼看了后讓你收獲很多,代碼思維和能力有較大的提升有哪些源代碼看了后讓你收獲很多,代碼思維和能力有較大的提升開(kāi)源的運(yùn)行原理從虛擬機(jī)工作流程看運(yùn)行原理。 自己實(shí)現(xiàn)集合框架 (三): 單鏈表的實(shí)現(xiàn) 自己實(shí)現(xiàn)集合框架 (三): 單鏈表的實(shí)現(xiàn) 基于 POI 封裝 ExcelUtil 精簡(jiǎn)的 Excel 導(dǎo)入導(dǎo)出 由于 poi 本身只是針對(duì)于 ...

    caspar 評(píng)論0 收藏0
  • Java常用八種排序算法與代碼實(shí)現(xiàn)精解

    摘要:直接插入排序的算法重點(diǎn)在于尋找插入位置。也稱(chēng)縮小增量排序,是直接插入排序算法的一種更高效的改進(jìn)版本。希爾排序是非穩(wěn)定排序算法。簡(jiǎn)單選擇排序常用于取序列中最大最小的幾個(gè)數(shù)時(shí)。將新構(gòu)成的所有的數(shù)的十位數(shù)取出,按照十位數(shù)進(jìn)行排序,構(gòu)成一個(gè)序列。 1.直接插入排序 直接插入排序算法是排序算法中最簡(jiǎn)單的,但在尋找插入位置時(shí)的效率不高?;舅枷刖褪菍⒁粋€(gè)待排序的數(shù)字在已經(jīng)排序的序列中尋找找到一個(gè)插...

    2501207950 評(píng)論0 收藏0
  • 八種js交換兩個(gè)變量的值方案總結(jié)

    摘要:假定期望交換和的值序號(hào)實(shí)現(xiàn)方案中間變量備注按位操作符只適用類(lèi)型只適用類(lèi)型有腦洞先執(zhí)行對(duì)象解構(gòu)賦值推薦數(shù)組解構(gòu)賦值簡(jiǎn)書(shū)首發(fā)轉(zhuǎn)載請(qǐng)注明來(lái)自簡(jiǎn)書(shū) 假定let a = 1,b=10;期望交換a和b的值 序號(hào) 實(shí)現(xiàn)方案 中間變量? 備注 1 let c; c = a; a = b; b = c; ? 2 a ^= b; b ^=a; a ^=b MDN-按位操作符, 只適...

    LiveVideoStack 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<