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

資訊專欄INFORMATION COLUMN

JS繼承這點(diǎn)兒事

kelvinlee / 303人閱讀

摘要:用對(duì)象冒充繼承構(gòu)造函數(shù)的屬性,用原型鏈繼承的方法。但是屬性暴露出了問(wèn)題,每一個(gè)對(duì)象都有一個(gè)屬性指向它的構(gòu)造函數(shù),而實(shí)例的構(gòu)造函數(shù)卻指向了,這會(huì)導(dǎo)致繼承鏈的錯(cuò)亂。

ECMAScript 實(shí)現(xiàn)繼承的方式不止一種。這是因?yàn)?JavaScript 中的繼承機(jī)制并不是明確規(guī)定的,而是通過(guò)模仿實(shí)現(xiàn)的。這意味著所有的繼承細(xì)節(jié)并非完全由解釋程序處理。可以根據(jù)需求決定適合的繼承方式。

原文鏈接

對(duì)象冒充

構(gòu)造函數(shù)使用this關(guān)鍵字給所有屬性和方法賦值(即采用類聲明的構(gòu)造函數(shù)方式)。因?yàn)闃?gòu)造函數(shù)只是一個(gè)函數(shù),所以可使ClassA構(gòu)造函數(shù)成為ClassB的方法,然后調(diào)用它。ClassB就會(huì)收到ClassA的構(gòu)造函數(shù)中定義的屬性和方法。

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

function ClassB(name,age) {
    this.classA = ClassA;
    this.classA(name);
    delete this.classA;
    this.age = age;
    this.sayAge = function(){
        console.log(this.age);
    }
}

var tom = new ClassA("Tom");
var jerry = new ClassB("Jerry",25);
tom.sayName();                         //"Tom"
jerry.sayName();                       //"Jerry"
jerry.sayAge();                        //25
console.log(tom instanceof ClassA);    //true
console.log(jerry instanceof ClassA);  //false
console.log(jerry instanceof ClassB);  //true

所有新屬性和新方法都必須在刪除了新方法的代碼行后定義,因?yàn)榭赡軙?huì)覆蓋超類的相關(guān)屬性和方法

對(duì)象冒充可以實(shí)現(xiàn)多重繼承
如果存在ClassA和ClassB,這時(shí)ClassC想繼承這兩個(gè)類,如下:

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

function ClassB(age){
    this.age = age;
    this.sayAge = function(){
        console.log(this.age);
    }
}

function ClassC(name,age){
    this.method = ClassA;
    this.method(name);
    
    this.method = ClassB;
    this.method(age);
    delete this.method;
}

var tom = new ClassC("Tom",25);
tom.sayName();                       //"Tom";
tom.sayAge();                        //25
console.log(tom instanceof ClassA);  //false
console.log(tom instanceof ClassB);  //false
console.log(tom instanceof ClassC);  //true

這種實(shí)現(xiàn)方式的缺陷是:如果兩個(gè)類ClassA和ClassB具有同名的屬性或方法,ClassB具有高優(yōu)先級(jí),因?yàn)樗鼜暮竺娴念惱^承。
由于這種繼承方法的流行,ECMAScript的第三版為Function對(duì)象加入了兩個(gè)方法,即call()和apply()。

call

call方法是與經(jīng)典的對(duì)象冒充方法最相似的方法。它的第一個(gè)參數(shù)用作this的對(duì)象,其他參數(shù)都直接傳遞給函數(shù)自身

function sayName(prefix) {
    console.log(prefix + this.name);
};

var tom = {};
tom.name = "Tom";

sayName.call(tom, "This is ");  //"This is Tom"

函數(shù)sayName在對(duì)象外定義,但也可以引用this。
call方法改寫對(duì)象冒充

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

function ClassB(name,age){
    //this.method = ClassA;
    //this.method(name);
    //delete this.method;
    ClassA.call(this,name);
    this.age = age;
    this.sayAge = function (){
        console.log(this.age);
    }
}

var tom = new ClassB("Tom",25);
tom.sayName();                       //"Tom"
tom.sayAge();                        //25
console.log(tom instanceof ClassA);  //false
console.log(tom instanceof ClassB);  //true

call方法替代了使用屬性引用ClassA的方式。

apply

apply方法有兩個(gè)參數(shù),用作this的對(duì)象和要傳遞給函數(shù)的參數(shù)數(shù)組

function sayName(prefex,mark) {
    console.log(prefex+ this.name+ mark);
};

var tom = {};
tom.name = "Tom";

sayName.apply(tom, ["This is ","!"]);  //"This is Tom!"

同樣可以使用apply改寫對(duì)象冒充

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

function ClassB(name,age){
    ClassA.apply(this,arguments);
    this.age = age;
    this.sayAge = function (){
        console.log(this.age);
    }
}

var tom = new ClassB("Tom",25);
tom.sayName();                       //"Tom"
tom.sayAge();                        //25  
console.log(tom instanceof ClassA);  //false
console.log(tom instanceof ClassB);  //true

只有超類中參數(shù)順序和子類中的參數(shù)完全一致時(shí)才可以傳遞參數(shù)數(shù)組

原型鏈

prototype對(duì)象是個(gè)模板,要實(shí)例化的對(duì)象都以這個(gè)模板為基礎(chǔ),prototype對(duì)象的任何屬性和方法都被傳遞給這個(gè)類的所有實(shí)例,原型鏈就是利用這種功能來(lái)實(shí)現(xiàn)繼承機(jī)制。

function ClassA() {}
ClassA.prototype.name = "Tom";
ClassA.prototype.sayName = function () {
    console.log(this.name);
};

function ClassB() {}
ClassB.prototype = new ClassA();
var tom = new ClassB();
tom.sayName();                       //"Tom"
console.log(tom instanceof ClassA);  //true
console.log(tom instanceof ClassB);  //true

這里把ClassB的prototype屬性設(shè)置稱ClassA的實(shí)例,避免逐個(gè)賦值prototpye屬性。
在調(diào)用ClassA時(shí)沒有設(shè)置參數(shù),因?yàn)樵谠玩溨幸_保構(gòu)造函數(shù)是無(wú)參的。
在原型鏈中,instanceof的結(jié)果也有了變化,對(duì)于ClassA和ClassB都返回了true。

因?yàn)閜rototype屬性的重指定,子類中的新屬性都必須出現(xiàn)在prototype被賦值后。

function ClassA() {}
ClassA.prototype.name = "Tom";
ClassA.prototype.sayName = function () {
    console.log(this.name);
};

function ClassB() {}
ClassB.prototype = new ClassA();
ClassB.prototype.age = 25;
ClassB.prototype.sayAge = function () {
    console.log(this.age);
};

var tom = new ClassA();
var jerry = new ClassB();
tom.sayName();                         //"Tom"
jerry.sayName();                       //"Tom"
jerry.name = "Jerry";
tom.sayName();                         //"Tom"
jerry.sayName();                       //"Jerry"
jerry.sayAge();                        //25
console.log(tom instanceof ClassA);    //true
console.log(jerry instanceof ClassA);  //true
console.log(jerry instanceof ClassB);  //true

原型鏈的缺陷是不能實(shí)現(xiàn)多重繼承,因?yàn)轭惖膒rototype會(huì)被重寫。

混合方式

對(duì)象冒充的問(wèn)題是必須使用構(gòu)造函數(shù)方式,而使用原型鏈就無(wú)法使用帶參數(shù)的構(gòu)造函數(shù),不過(guò),可以試試兩者結(jié)合。
用對(duì)象冒充繼承構(gòu)造函數(shù)的屬性,用原型鏈繼承prototype的方法。

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

function ClassB(name, age) {
    ClassA.call(this, name);
    this.age = age;
}
ClassB.prototype = new ClassA();
ClassB.prototype.sayAge = function () {
    console.log(this.age);
};

var tom = new ClassA("Tom");
var jerry = new ClassB("Jerry",25);
console.log(tom instanceof ClassA);                    //true
console.log(jerry instanceof ClassA);                  //true
console.log(jerry instanceof ClassB);                  //true
console.log(jerry.constructor === ClassA);             //true
console.log(ClassB.prototype.constructor === ClassA);  //true

在ClassB構(gòu)造函數(shù)中用對(duì)象冒充繼承了ClassA的name屬性,用原型鏈繼承了ClassA的sayName方法,由于使用了原型鏈繼承方式,instanceof運(yùn)行方式正常。
但是constructor屬性暴露出了問(wèn)題,每一個(gè)prototype對(duì)象都有一個(gè)constructor屬性指向它的構(gòu)造函數(shù),而ClassB實(shí)例的構(gòu)造函數(shù)卻指向了ClassA,這會(huì)導(dǎo)致繼承鏈的錯(cuò)亂。可以手動(dòng)修改constructor的指向。

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

function ClassB(name, age) {
    ClassA.call(this, name);
    this.age = age;
}
ClassB.prototype = new ClassA();
ClassB.prototype.constructor = ClassB;
ClassB.prototype.sayAge = function () {
    console.log(this.age);
};

var tom = new ClassA("Tom");
var jerry = new ClassB("Jerry",25);
console.log(tom instanceof ClassA);                    //true
console.log(jerry instanceof ClassA);                  //true
console.log(jerry instanceof ClassB);                  //true
console.log(ClassA.constructor === ClassB);            //false
console.log(jerry.constructor === ClassA);             //false
console.log(ClassB.prototype.constructor === ClassA);  //false
直接繼承原型鏈

為了節(jié)省內(nèi)存,可以不執(zhí)行創(chuàng)建ClassA實(shí)例,直接讓ClassB的原型指向ClassA的原型

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

function ClassB(name, age) {
    ClassA.call(this, name);
    this.age = age;
}
ClassB.prototype = ClassA.prototype;
ClassB.prototype.constructor = ClassB;
ClassB.prototype.sayAge = function () {
    console.log(this.age);
};

var tom = new ClassA("Tom");
var jerry = new ClassB("Jerry",25);
console.log(ClassA.prototype.hasOwnProperty("sayAge"));  //true
console.log(ClassA.prototype.constructor === ClassB);   //true

這樣的缺陷是由于直接修改原型鏈指向,對(duì)于ClassB原型鏈中的屬性也會(huì)影響到ClassA上,于是就出現(xiàn)了ClassA具有sayAge方法、ClassA的構(gòu)造函數(shù)屬性為ClassB。

空對(duì)象作中介

為解決直接繼承原型鏈的缺點(diǎn),可以利用一個(gè)空對(duì)象作為中介。

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

function ClassB(name, age) {
    ClassA.call(this, name);
    this.age = age;
}

var fn = function(){};
fn.prototype = ClassA.prototype;
ClassB.prototype = new fn();
ClassB.prototype.constructor = ClassB;
ClassB.prototype.sayAge = function () {
    console.log(this.age);
};
console.log(ClassA.prototype.hasOwnProperty("sayAge"));  //false
console.log(ClassA.prototype.constructor === ClassB);    //false   

雖然還是創(chuàng)建了對(duì)象實(shí)例,但由于空對(duì)象幾乎不占內(nèi)存,修改ClassB的原型也不會(huì)影響到ClassA。

封裝成extends方法

function extends(child,parent){
    var fn = function (){};
    fn.prototype = parent.prototype;
    child.prototype = new fn();
    child.prototype.constructor = child;
    child.super = parent.prototype;
}

JS的靈活性使我們可以通過(guò)多種方式實(shí)現(xiàn)繼承,了解其中的原理和實(shí)現(xiàn)可以幫助我們?cè)诓煌膱?chǎng)景中選擇適合的方法。

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

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

相關(guān)文章

  • 寫給在迷茫中前行的前端學(xué)習(xí)/工作者

    摘要:我從今年的月份開始在知乎上連續(xù)回答前端開發(fā)相關(guān)的問(wèn)題,至今已有將近三個(gè)月,回顧寫過(guò)的一百多條回答,不少是給迷茫的前端工作者的建議。今天我把我的思考提煉整理成文,希望能給予在迷茫中前行中的前端學(xué)習(xí)工作者一些有用的建議。 本文首發(fā)于知乎專欄——前端指南作者:Mark MFS老師轉(zhuǎn)載請(qǐng)注明來(lái)源。 我從今年的2月份開始在知乎上連續(xù)回答前端開發(fā)相關(guān)的問(wèn)題,至今已有將近三個(gè)月,回顧寫過(guò)的一百多條回...

    羅志環(huán) 評(píng)論0 收藏0
  • 體驗(yàn)javascript之美6:如果你覺得什么都會(huì)了或者不知道js學(xué)什么了看這里-面向?qū)ο缶幊?/b>

    摘要:面向過(guò)程函數(shù)式編程面向?qū)ο缶幊痰诙€(gè)并不是大家理解的那樣,我們先說(shuō)舉個(gè)現(xiàn)實(shí)例子就明白了。多說(shuō)一句函數(shù)是編程是非常強(qiáng)大也是我最喜歡的,以后再說(shuō),我們先說(shuō)面向?qū)ο缶幊獭? 概述 當(dāng)大家已經(jīng)把js的語(yǔ)言基礎(chǔ)理解了,然后能夠?qū)懗鲆恍┖?jiǎn)單的例子了,這個(gè)時(shí)候基本上達(dá)到了一年工作經(jīng)驗(yàn)的水平,而自己能夠獨(dú)立的寫一些小功能,完成一些小效果,或者臨摹修改一些比較復(fù)雜的插件的時(shí)候差不多就是兩年工作經(jīng)驗(yàn)的水平,...

    changfeng1050 評(píng)論0 收藏0
  • js面向?qū)ο鬁\析--繼承那些

    摘要:有需要還可以修改指向謙龍寄生組合式繼承思路是通過(guò)借用構(gòu)造函數(shù)來(lái)繼承屬性,通過(guò)原型鏈的混合形式來(lái)繼承方法改變執(zhí)行環(huán)境實(shí)現(xiàn)繼承有需要還可以修改指向謙龍謙龍拷貝繼承該方法思路是將另外一個(gè)對(duì)象的屬性和方法拷貝至另一個(gè)對(duì)象使用遞歸 前言 js中實(shí)現(xiàn)繼承的方式只支持實(shí)現(xiàn)繼承,即繼承實(shí)際的方法,而實(shí)現(xiàn)繼承主要是依靠原型鏈來(lái)完成的。 原型鏈?zhǔn)嚼^承 該方式實(shí)現(xiàn)的本質(zhì)是重寫原型對(duì)象,代之以一個(gè)新類型的實(shí)例...

    molyzzx 評(píng)論0 收藏0
  • 從-1開始的ES6探索之旅02:小伙子,你對(duì)象咋來(lái)的?續(xù)篇 - 你的對(duì)象班(class)里來(lái)的?

    摘要:這是因?yàn)樽宇悰]有自己的對(duì)象,而是繼承父類的對(duì)象,然后對(duì)其進(jìn)行加工。 溫馨提示:作者的爬坑記錄,對(duì)你等大神完全沒有價(jià)值,別在我這浪費(fèi)生命溫馨提示-續(xù):你們要非得看,我也攔不住,但是至少得準(zhǔn)備個(gè)支持ES6的Chrome瀏覽器吧?溫馨提示-再續(xù):ES6簡(jiǎn)直了,放著不用簡(jiǎn)直令人發(fā)指! 書接上回,即便是程序員,也還是能夠通過(guò)自己的努力辛辛苦苦找到合適對(duì)象的,見前文《javascript對(duì)象不完全...

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

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

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<