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

資訊專欄INFORMATION COLUMN

javascript之模擬類繼承

Jochen / 2102人閱讀

摘要:歡迎關(guān)注我的博客正文讓我來(lái)構(gòu)造函數(shù)其實(shí),模擬一個(gè)類的方式非常的簡(jiǎn)單構(gòu)造函數(shù)。我們先來(lái)看一個(gè)例子這里通過(guò)構(gòu)造函數(shù)模擬出來(lái)的類,其實(shí)和其他語(yǔ)言的類行為上是基本一致的,唯一的區(qū)別就是它不具備私有方法。

前言

ES6時(shí)代的來(lái)臨,使得類繼承變得如此的圓滑。但是,你有思考過(guò)ES6的類繼承模式嗎?如何去實(shí)現(xiàn)它呢?

類繼承對(duì)于JavaScript來(lái)說(shuō),實(shí)現(xiàn)方式與Java等類語(yǔ)言大不相同。熟悉JavaScript的開(kāi)發(fā)者都清楚,JavaScript是基于原型模式的。那么,在es6沒(méi)有出來(lái)之前,js是如何繼承的呢?這是一個(gè)非常有意思的話題。希望帶著疑問(wèn)看文章,或許對(duì)你的提升會(huì)更加巨大。如果你喜歡我的文章,歡迎評(píng)論,歡迎Star~。歡迎關(guān)注我的github博客

正文 讓我來(lái)——構(gòu)造函數(shù)

其實(shí),js模擬一個(gè)類的方式非常的簡(jiǎn)單——構(gòu)造函數(shù)?;蛟S,這是所有人都在普遍使用的方式。我們先來(lái)看一個(gè)例子:

function Person(name){
      this.name = name;
}

Person.prototype.sayName = function(){
     console.log(this.name);
}

const person = new Person("zimo");

person.sayName();       //zimo

這里通過(guò)構(gòu)造函數(shù)模擬出來(lái)的類,其實(shí)和其他語(yǔ)言的類行為上是基本一致的,唯一的區(qū)別就是它不具備私有方法。而且,他們同樣是通過(guò)new操作符來(lái)進(jìn)行實(shí)例化的,但是js的new操作與其它語(yǔ)言的new操作又會(huì)有所不同。比方說(shuō):

const person = Person("zimo");
console.log(person)    //undefined

構(gòu)造函數(shù)前面沒(méi)有加new的情況下,會(huì)導(dǎo)致這個(gè)對(duì)象沒(méi)有返回值來(lái)進(jìn)行賦值。但是,在類語(yǔ)言中,在類名前不使用new是會(huì)報(bào)錯(cuò)的。

下面,我們應(yīng)該進(jìn)一步來(lái)看一下js的new操作符的原理,以及實(shí)現(xiàn)。

你懂我——new操作符

new方法原理:

創(chuàng)建一個(gè)新的對(duì)象

將對(duì)象的__proto__指向構(gòu)造函數(shù)的原型

調(diào)用構(gòu)造函數(shù)

返回新對(duì)象

js代碼實(shí)現(xiàn)部分:

const person = new Person(args);
//相當(dāng)于
const person = Person.new(args);
Function.prototype.new = function(){
       let obj = new Object();
       obj.__proto__ = this.prototype;
       const ret = this.apply(obj, arguments);
       return (typeof ret == "object" && ret) || obj;
}

到此為止,js如何去模擬類,我們已經(jīng)講述完了。接下來(lái),我們應(yīng)該看一下如何去實(shí)現(xiàn)類似與其他語(yǔ)言的類繼承模式。

盡管ES6已經(jīng)對(duì)extends關(guān)鍵詞進(jìn)行了實(shí)現(xiàn),但是原理性的知識(shí),我們應(yīng)該需要明白。

初印象——類繼承

先來(lái)看一個(gè)場(chǎng)景,無(wú)論是狗或者是貓,它們都有一個(gè)共同的類animal,如圖:

在真實(shí)開(kāi)發(fā)中,我們必須去實(shí)現(xiàn)類與類之間的繼承關(guān)系,不然的話,我們就必須重復(fù)地去命名構(gòu)造函數(shù)(這樣的方式是丑陋的)。

所以,像上述的場(chǎng)景,開(kāi)發(fā)過(guò)程中多的數(shù)不勝數(shù),但是本質(zhì)都是不變的。接下來(lái),那我們以一個(gè)例子來(lái)做說(shuō)明,并且明白大致是如何去實(shí)現(xiàn)的。

例子:我們需要去構(gòu)造一個(gè)交通工具類,該類具備屬性:輪子、速度和顏色(默認(rèn)為黑),它還具備方法run(time)返回距離。之后,我們還需要去通過(guò)該類繼承一個(gè)‘汽車’類和一個(gè)‘單車’類。

如圖:

實(shí)現(xiàn):

function Vehicle(wheel, speed){      //首先構(gòu)造一個(gè)交通工具類
    this.wheel = wheel;
    this.speed = speed;
    this.color = "black";
}

Vehicle.prototype.run = function(time){    //在它的原型上定義方法
    return this.speed * time;
}

function Car(wheel, speed, brand){     //通過(guò)在汽車類中去調(diào)用父類
    Vehicle.call(this, wheel, speed);
    this.brand = brand;
}

Car.prototype = new Vehicle();      //將汽車類的原型指向交通工具的實(shí)例

function Bicycle(wheel, speed, owner){        //同樣,構(gòu)造一個(gè)自行車類,在其中調(diào)用父類
    Vehicle.call(this, wheel, speed);
    this.owner = owner;
}

Bicycle.prototype = new Vehicle();             //將其原型指向交通工具實(shí)例

const car = new Car(4, 10, "baoma");

const bicycle = new Bicycle(2, 5, "zimo");

console.log(car.run(10));   //100

console.log(bicycle.run(10));   //50

這樣子,就實(shí)現(xiàn)了類的繼承。

大致的思路是:在繼承類中調(diào)用父類,以及將繼承類的原型賦值為父類的實(shí)例。

但是,每次實(shí)現(xiàn)如果都是這樣子的話,又會(huì)顯得非常的累贅,我們并沒(méi)有將可以重復(fù)使用的部分。因此,我們需要將不變的部分進(jìn)行封裝,封裝成一個(gè)方法,然后將可變的部分當(dāng)中參數(shù)傳遞進(jìn)來(lái)。

接下來(lái),我們來(lái)分析一下類繼承的封裝方法extend。

真實(shí)的我——繼承封裝

首先,我們來(lái)看一下,我們需要實(shí)現(xiàn)怎樣的繼承:

function Animal(name){         //構(gòu)造一個(gè)動(dòng)物類
  this.name = name;
}
Animal.prototype.sayName = function(){    
  console.log("My name is " + this.name);
}

/**
extends方法其中包含子類的constructor、自身的屬性、和來(lái)自父元素繼承的屬性
*/

var Dog = Animal.extends({                            //使用extends方法來(lái)實(shí)現(xiàn)類的封裝
  constructor: function(name, lan){
    this._super(name);
    this.lan = lan
  },
  sayname: function(){
    this._super.sayName();
  },
  sayLan: function(){
   console.log(this.lan);
  }
});

var animal = new Animal("animal");
var dog = new Dog("dog", "汪汪汪");

animal.sayName();    //My name is animal
dog.sayName();    // My name is dog
dog.sayLan();    // "汪汪汪"

其中的extend方法是我們需要去實(shí)現(xiàn)的,在實(shí)現(xiàn)之前,我們可以來(lái)對(duì)比一下ES6的語(yǔ)法

class Animal {
  constructor(name){
    this.name = name;
  }

  sayName(){
    console.log("My name is " + this.name);
  }
}

/**
對(duì)比上面的extend封裝和es6的語(yǔ)法,我們會(huì)發(fā)現(xiàn),其實(shí)差異并沒(méi)有太大
*/

class Dog extends Animal{
  constructor(name, lan){
    super(name);

    this.lan = lan;
  }

  sayName(){
    super.sayName();
  }

  sayLan(){
    console.log(this.lan);
  }
}

其實(shí),很多地方是相似的,比方說(shuō)super和this._super。這個(gè)對(duì)象其實(shí)是看起來(lái)是父構(gòu)造函數(shù),因?yàn)樗梢灾苯诱{(diào)用this._super(name),但它同時(shí)還具備父構(gòu)造函數(shù)原型上的函數(shù),因此我們可以把它稱為父包裝器。但是,必須保證的是_super中的函數(shù)對(duì)象上下文必須都是指向子構(gòu)造函數(shù)的。

使用一張簡(jiǎn)陋的圖來(lái)表示整個(gè)關(guān)系的話,如圖:

下面我們來(lái)實(shí)現(xiàn)一下這個(gè)extend方法。

Function.prototype.extend = function(props){
  var Super = this;

  var Temp = function(){};

  Temp.prototype = Super.prototype;

  var superProto = new Temp();   //去創(chuàng)建一個(gè)指向Super.prototype的實(shí)例

  var _super = function(){   //創(chuàng)建一個(gè)父類包裝器
    return Super.apply(this, arguments);
  }

  var Child = function(){
    if(props.constructor){
      props.constructor.apply(this, arguments);
    }

    for(var i in Super.prototype){
      _super[i] = Super.prototype[i].bind(this);   //確保Super的原型方法拷貝過(guò)來(lái)時(shí),this指向Child構(gòu)造函數(shù)
    }

  }

  Child.prototype = superProto;               //將子類的原型指向父類的純實(shí)例
  Child.prototype._super = _super;                //構(gòu)建一個(gè)引用指向父類的包裝器

  for(var i in props){
    if( i !== "constructor"){
      Child.prototype[i] = props[i];   //將props中方法放到Child的原型上面
    }
  }

  return Child;
}
總結(jié)

繼承的一些內(nèi)容就分析到這里。其實(shí),自從ES6標(biāo)準(zhǔn)出來(lái)之后,類的繼承已經(jīng)非常普遍了,因?yàn)檎嫘暮糜谩5?,也是越?lái)越有人不懂得如何去理解這個(gè)繼承的原理了。其實(shí)ES6中的繼承的實(shí)現(xiàn),也是挺簡(jiǎn)單的。

如果你對(duì)我寫的有疑問(wèn),可以評(píng)論,如我寫的有錯(cuò)誤,歡迎指正。你喜歡我的博客,請(qǐng)給我關(guān)注Star~呦。大家一起總結(jié)一起進(jìn)步。歡迎關(guān)注我的github博客

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

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

相關(guān)文章

  • JavaScript深入new的模擬實(shí)現(xiàn)

    摘要:深入系列第十二篇,通過(guò)的模擬實(shí)現(xiàn),帶大家揭開(kāi)使用獲得構(gòu)造函數(shù)實(shí)例的真相一句話介紹運(yùn)算符創(chuàng)建一個(gè)用戶定義的對(duì)象類型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象類型之一也許有點(diǎn)難懂,我們?cè)谀M之前,先看看實(shí)現(xiàn)了哪些功能。 JavaScript深入系列第十二篇,通過(guò)new的模擬實(shí)現(xiàn),帶大家揭開(kāi)使用new獲得構(gòu)造函數(shù)實(shí)例的真相 new 一句話介紹 new: new 運(yùn)算符創(chuàng)建一個(gè)用戶定義的對(duì)象類型的實(shí)例或具...

    tianlai 評(píng)論0 收藏0
  • JavaScript深入繼承的多種方式和優(yōu)缺點(diǎn)

    摘要:深入系列第十五篇,講解各種繼承方式和優(yōu)缺點(diǎn)。優(yōu)點(diǎn)融合原型鏈繼承和構(gòu)造函數(shù)的優(yōu)點(diǎn),是中最常用的繼承模式。寄生組合式繼承為了方便大家閱讀,在這里重復(fù)一下組合繼承的代碼組合繼承最大的缺點(diǎn)是會(huì)調(diào)用兩次父構(gòu)造函數(shù)。 JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 寫在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 但是注意: 這篇文章更像是筆記,哎...

    JackJiang 評(píng)論0 收藏0
  • JavaScript 工作原理十五-類和繼承及 Babel 和 TypeScript 代碼轉(zhuǎn)換探秘

    摘要:使用新的易用的類定義,歸根結(jié)底也是要?jiǎng)?chuàng)建構(gòu)造函數(shù)和修改原型。首先,它把構(gòu)造函數(shù)當(dāng)成單獨(dú)的函數(shù)且包含類屬性集。該節(jié)點(diǎn)還儲(chǔ)存了指向父類的指針引用,該父類也并儲(chǔ)存了構(gòu)造函數(shù),屬性集和及父類引用,依次類推。 原文請(qǐng)查閱這里,略有刪減,本文采用知識(shí)共享署名 4.0 國(guó)際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第...

    GeekGhc 評(píng)論0 收藏0
  • JavaScript 工作原理十五-類和繼承及 Babel 和 TypeScript 代碼轉(zhuǎn)換探秘

    摘要:使用新的易用的類定義,歸根結(jié)底也是要?jiǎng)?chuàng)建構(gòu)造函數(shù)和修改原型。首先,它把構(gòu)造函數(shù)當(dāng)成單獨(dú)的函數(shù)且包含類屬性集。該節(jié)點(diǎn)還儲(chǔ)存了指向父類的指針引用,該父類也并儲(chǔ)存了構(gòu)造函數(shù),屬性集和及父類引用,依次類推。 原文請(qǐng)查閱這里,略有刪減,本文采用知識(shí)共享署名 4.0 國(guó)際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第...

    BigNerdCoding 評(píng)論0 收藏0
  • JavaScript深入bind的模擬實(shí)現(xiàn)

    摘要:也就是說(shuō)當(dāng)返回的函數(shù)作為構(gòu)造函數(shù)的時(shí)候,時(shí)指定的值會(huì)失效,但傳入的參數(shù)依然生效。構(gòu)造函數(shù)效果的優(yōu)化實(shí)現(xiàn)但是在這個(gè)寫法中,我們直接將,我們直接修改的時(shí)候,也會(huì)直接修改函數(shù)的。 JavaScript深入系列第十一篇,通過(guò)bind函數(shù)的模擬實(shí)現(xiàn),帶大家真正了解bind的特性 bind 一句話介紹 bind: bind() 方法會(huì)創(chuàng)建一個(gè)新函數(shù)。當(dāng)這個(gè)新函數(shù)被調(diào)用時(shí),bind() 的第一個(gè)參數(shù)...

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

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

0條評(píng)論

閱讀需要支付1元查看
<