国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【呆萌の研究】JavaScript常見的繼承方式

馬永翠 / 933人閱讀

摘要:構(gòu)造函數(shù)構(gòu)造操作符調(diào)用的函數(shù)就是構(gòu)造函數(shù)。其和其構(gòu)造函數(shù)的指向相同。而構(gòu)造函數(shù)屬性指向的對象帶有屬性,指向函數(shù)自身。,回歸構(gòu)造函數(shù)繼承,仔細(xì)看看誕生的嘻嘻和哈哈兩位同學(xué)可以看到兩個實例都擁有了和兩個屬性,因為方法的運行類似于執(zhí)行了和。

最近在看《JavaScript設(shè)計模式》,然后開篇復(fù)習(xí)了JavaScript中的幾種繼承方式,自己似乎也沒有怎么仔細(xì)探究過,目前自己沒怎么碰到過應(yīng)用的場景(噗),所以借這次機會好好來屢屢思路。

方式1 類式繼承

例子

function Person() {
    this.telephone = ["000-0000-0000"];
}

function Student(className) {
    this.className = className;
}

Student.prototype = new Person();
var Haha = new Student(1);
var Xixi = new Student(2);

創(chuàng)建好父類和子類。聯(lián)系他們的方式是把學(xué)生的prototype指向一個人的實例。

問:prototype是什么?
幾乎任何對象有一個[[prototype]]屬性,在標(biāo)準(zhǔn)中,[[prototype]]一個隱藏屬性,指向的是這個對象的原型。而它的指向是由構(gòu)造該對象的方法決定的:
1.對象字面量構(gòu)造:其[[prototype]]指向Object.prototype。

var person = {};

2.構(gòu)造函數(shù)構(gòu)造:new操作符調(diào)用的函數(shù)就是構(gòu)造函數(shù)。其[[prototype]]和其構(gòu)造函數(shù)的prototype指向相同。而構(gòu)造函數(shù)prototype屬性指向的對象帶有constructor屬性,指向函數(shù)自身。

function Person(){}
var person = new Person();

此圖為Person的prototype內(nèi)容,可以看到constructor屬性實際指向的就是Person()函數(shù)。(小綠色框框內(nèi)和外面綠色框框其實是同一個內(nèi)容)。

3.Object.create構(gòu)造的。

var person = {};
var Haha = Object.create(person);

這里對象Haha的[[prototype]]指向?qū)ο髉erson。也可以寫null,此時對象Haha就沒有原型。

首先要分清楚類和實例,在控制臺顯示中,只有類才會有prototype屬性,而實例是擁有一個名為_proto_的屬性,它會指向構(gòu)造它函數(shù)的原型,兩者本質(zhì)都是一個指針。

function Person() {
   this.telephone = ["000-0000-0000"];
}
var Hehe = new Person(); 
console.log(Person.prototype);
console.log(Hehe);

以上代碼運行結(jié)果:

可以瞧見,這里Hehe的_proto_是指向了Person.prototype

問:new關(guān)鍵字的作用是什么?
new關(guān)鍵字運作的過程如下,引用自《JavaScript》高級程序設(shè)計:

1、創(chuàng)建一個空對象,并且 this 變量引用該對象,同時還繼承了該函數(shù)的原型。  2、屬性和方法被加入到 this 引用的對象中。 
3、新創(chuàng)建的對象由 this 所引用,并且最后隱式的返回 this。

簡單來說,它創(chuàng)建了一個空對象,指定了原型,把屬性方法進(jìn)行拷貝,并把this指向進(jìn)行了改變。假如我們把上面的代碼改成:

function Person() {
 this.telephone = ["000-0000-0000"];
}
        
var Hehe = Person();
console.log(Hehe.telephone);

去掉new關(guān)鍵詞賦予Person(),會報錯,而輸出window.telphone得到的就是["000-0000-0000"]。因為函數(shù)的返回值(沒有返回值所以是undefined)賦予給了Hehe,嘗試去讀取undefined的屬性,報錯了。而此時函數(shù)運行中的this是全局變量window。

So,回歸類式繼承,仔細(xì)看看誕生的嘻嘻和哈哈兩位同學(xué)

會發(fā)現(xiàn),各自都有自己的班級名屬性,但是原型指向的是同一個Person實例,所以如果嘻嘻有兩個號碼,或者他要更改自己的號碼,那哈哈的電話號碼也會發(fā)生變化,他們只能共享這個電話號碼。

方式2 構(gòu)造函數(shù)繼承

例子

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

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

function Student(name, className) {
    this.className = className;
    Person.call(this, name);
}
var Haha = new Student("Haha", 1);
var Xixi = new Student("Xixi", 2);

問:call函數(shù)的運作過程?
call函數(shù)和apply函數(shù)的作用相同,不同之處就是apply函數(shù)只能傳入2個參數(shù),而call函數(shù)可以有多個。F.call(thisArg,[arg1……]) 函數(shù)的運作過程如下(來源網(wǎng)絡(luò)):

1.先判斷F是否為一個函數(shù),如果不是一個函數(shù),那么將拋出TypeError異常。 
2.創(chuàng)建一個內(nèi)部類型空列表list
3.然后如果參數(shù)除去thisArg外還有其他參數(shù)的話,就將這些值添加到list中
4.thisArg和list作為F內(nèi)部屬性[[Call]]的參數(shù)傳入調(diào)用進(jìn)行函數(shù)的執(zhí)行操作

簡而言之就是它把一個函數(shù)的對象上下文改成了由 thisArg指定的新對象。

So,回歸構(gòu)造函數(shù)繼承,仔細(xì)看看誕生的嘻嘻和哈哈兩位同學(xué)

可以看到兩個實例都擁有了className和name兩個屬性,因為call方法的運行類似于執(zhí)行了Haha.name="Haha"Xixi.name="Xixi"
但是因為沒有與父類的原型相聯(lián)系,所以父類原型中的方法,不能得到繼承。運行Haha.showName()會得到報錯。

方式3 組合繼承

例子

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

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

function Student(name, className) {
    this.className = className;
    Person.call(this, name);
}
Student.prototype = new Person();
Student.prototype.showClassName = function() {
     console.log(this.className);
}

var Haha = new Student("Haha", 1);
var Xixi = new Student("Xixi", 2);

組合繼承綜合了類式繼承和構(gòu)造函數(shù)繼承,在把父類的屬性繼承后,把子類的原型指向了父類實例,這樣就可以繼承父類原型的方法了。
但是這里相當(dāng)于使用了兩次父類函數(shù),并且子類不是父類的實例,子類的原型是父類的實例,所以還會有更好的方法。

方式4 原型繼承
function inheritObject(o) {
 function F() {}
 F.prototype = o;
 return new F();
}

var person = {
 name: "unknown",
 telephone: ["000-0000-0000"]
}

var Xixi = inheritObject(person);
Xixi.name = "Xixi";
Xixi.telephone.push("111-1111-1111");

var Haha = inheritObject(person);
Haha.name = "Haha";

仔細(xì)看看誕生的嘻嘻和哈哈兩位同學(xué)

這里.name給Xixi實例添加了一個自己的name屬性,而push操作是直接影響原型中引用變量,所以改進(jìn)之后又有了下面這種方式。
在這里我產(chǎn)生了一個疑問,為什么name屬性是自己添加新的,而telephone是采用原來的。于是添加了一個age屬性,執(zhí)行Xixi.age++操作。

這里可以看到實例重新添加了一個age屬性,所以我們可以說只要是改變原型屬性的值,就會把新的屬性加在實例上,引用不改變是因為引用的地址還沒有改變。

方式5 寄生式繼承

寄生式繼承是在原型繼承的基礎(chǔ)之上,我們需要再添加一下代碼:

function createPerson(obj) {
 var o = inheritObject(obj);
 o.getName = function(){
  console.log(name);
 }
 return o;
}

這樣就給得到的對象添加了公共方法。

方式6 寄生組合式繼承

寄生組合式繼承是為了彌補組合式繼承的缺點,是在寄生式繼承+構(gòu)造函數(shù)繼承組合而成的:

function inheritObject(o) {
 function F() {}
 F.prototype = o;
 return new F();
}
function inheritPrototype(subClass, superClass) {
 //復(fù)制一份父類原型
 var p = inheritObject(superClass.prototype);
 //修正重寫子類原型導(dǎo)致constructor屬性被修改
 p.constructor = subClass;
 //設(shè)置子類原型
 subClass.prototype = p;
}

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

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

function Student(name, className) {
    this.className = className;
    Person.call(this, name);
}

inheritPrototype(Student, Person);

Student.prototype.showClassName = function() {
     console.log(this.className);
}

var Xixi = new Student("Xixi",2);
var Haha = new Student("Haha",1);

以下為嘻嘻和哈哈的內(nèi)容:

可以對比一下組合式繼承的結(jié)果:

不同的地方在于把子類原型的構(gòu)造函數(shù)改成了實例對應(yīng)的構(gòu)造函數(shù),在組合繼承中子類原型直屬并沒有constructor屬性。

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/93124.html

相關(guān)文章

  • 萌の研究JavaScriptの閉包

    摘要:為什么會產(chǎn)生閉包究其根本,是因為代表的函數(shù)包含的作用域。而在作用域鏈中,外部函數(shù)的活動對象始終處于第二位,外部函數(shù)的外部函數(shù)的活動對象處于第三位直到作為作用域鏈終點的全局執(zhí)行環(huán)境。 前言 此文的內(nèi)容主要是來自看書的總結(jié)+小小的實踐哦~會不斷更新總結(jié)。 什么是閉包 書上是這樣定義閉包的: 有權(quán)訪問另一個函數(shù)作用域中變量的函數(shù)。 舉一個例子: function test(){ va...

    CHENGKANG 評論0 收藏0
  • 萌の研究】圣杯布局引發(fā)對margin負(fù)值研究

    摘要:問題起源以前一直就聽說圣杯布局,但是沒有怎么去用過,然后這次偶然接觸到了,就學(xué)習(xí)了一下。繼續(xù)試驗我們可以嘗試改變的值,去看看位置的變化。為了方便我們計算,另外寫了一個類似的布局,內(nèi)容區(qū)的寬度是,三個的寬度也都是。 問題の起源 以前一直就聽說圣杯布局,但是沒有怎么去用過,然后這次偶然接觸到了,就學(xué)習(xí)了一下。這是一個我從別人寫的文章中復(fù)制過來的,關(guān)于圣杯布局的比較簡單的說明 通過縮放頁面就...

    zhangke3016 評論0 收藏0
  • 萌の體驗】vue.js初次體驗

    摘要:官方默認(rèn)項目是存放了一個為的打開文件夾有一個,還有一個名為組件的文件夾,里面放了一個文件。部分我們會發(fā)現(xiàn)這幾排字就是顯示在頁面的幾排文字部分這其中的這個文件引入了,還有上述的。結(jié)合查詢其他說法,就是說它會把是的元素以形式替換。 前言 我很早就想來學(xué)習(xí)學(xué)習(xí)vue.js啦,終于有了那么一些空閑的時間可以拿來學(xué)習(xí),于是從前天開始我就每天抽一個多小時來體驗vue.js。當(dāng)然啦,因為是小白入門,...

    wdzgege 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<