摘要:繼承創(chuàng)建子類型的實例時,不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)。借用構(gòu)造函數(shù)偽造對象經(jīng)典繼承在子類型構(gòu)造函數(shù)內(nèi)部調(diào)用超類型構(gòu)造函數(shù)。組合繼承使用原型鏈實現(xiàn)對原型屬性和方法的繼承,而通過構(gòu)造函數(shù)來實現(xiàn)實例屬性的繼承。
JS繼承 原型鏈 構(gòu)造函數(shù)、原型、實例的關(guān)系
每個構(gòu)造函數(shù)都有一個原型對象,原型對象包含一個指向構(gòu)造函數(shù)的指針,而實例包含一個指向構(gòu)造函數(shù)的指針。
原型鏈的構(gòu)建是通過將一個類型的實例賦值給另一個構(gòu)造函數(shù)的原型實現(xiàn)。
function SuperType(){ this.property=true; } SuperType.prototype.getSuperValue=function () { return this.property; }; function SubType(){ this.subproperty=false; } //繼承SuperType SubType.prototype=new SuperType(); SuperType.prototype.getSubValue=function () { return this.subproperty; } var instance=new SubType(); console.log(instance.getSubValue()); //false console.log(instance.getSuperValue()); //true
SubType繼承SuperType是通過創(chuàng)建SuperType實例,并將該實例賦給SubType.prototype實現(xiàn)的。本質(zhì)是重寫原型對象,代之以一個新類型的實例。
instance指向SubType的原型,SubType的原型又指向SuperType的原型。要注意的是instance.constructor現(xiàn)在指向的是SuperType,應(yīng)為SubType的原型指向了SuperType的原型,而該原型對象的constructor屬性指向的SuperType。
調(diào)用instance.getSuperValue()會經(jīng)歷一下三個步驟:
1)搜索實例
2)搜索SubType.prototype
3)搜索SuperType.prototype,最后一步才會找到該方法。在找不到屬性或方法的情況下,搜索過程總要一環(huán)一環(huán)地前行到原型鏈末端為止。
1.instanceof
instance instanceof Object
2.isPrototypeOf
Object.prototype.isPrototypeOf(instance)
1.子類型需要覆蓋超類型中的某個方法,或需要添加超類型中不存在的某個方法。給原型添加方法的代碼要放在替換原型的語句后面。
function SuperType(){ this.property=true; } SuperType.prototype.getSuperValue=function () { return this.property; }; function SubType(){ this.subproperty=false; } //繼承SuperType SubType.prototype=new SuperType(); //添加新方法 SuperType.prototype.getSubValue=function () { return this.subproperty; } //重寫超類型中的方法 SubType.prototype.getSuperValue=function () { return false; } var instance=new SubType(); console.log(instance.getSuperValue());
2.通過原型鏈實現(xiàn)繼承時,不能使用對象字面量創(chuàng)建原型方法。這樣會重寫原型鏈。
function SuperType(){ this.property=true; } SuperType.prototype.getSuperValue=function () { return this.property; }; function SubType(){ this.subproperty=false; } //繼承SuperType SubType.prototype=new SuperType(); SubType.prototype={ getSubValue:function () { return this.subproperty; } }; var instance=new SubType(); console.log(instance.getSuperValue()); //error
以上代碼先把SuperType的實例賦值給原型,緊接著又將原型替換成一個對象字面量。由于現(xiàn)在的原型包含的是一個Object實例,而非SuperType的實例。因此,原來的SuperType和SubType之間的原型鏈被切斷。
原型鏈的問題1.包含引用類型的原型屬性會被所有實例共享。
function SuperType(){ this.nums=[1,2]; } function SubType(){ } //繼承SuperType SubType.prototype=new SuperType(); var instance=new SubType(); instance.nums.push(5); console.log(instance.nums); //[1,2,5] var instance1=new SubType(); instance1.nums.push(0); console.log(instance1.nums); //[1,2,5,0]
2.創(chuàng)建子類型的實例時,不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)。
借用構(gòu)造函數(shù)(偽造對象/經(jīng)典繼承)在子類型構(gòu)造函數(shù)內(nèi)部調(diào)用超類型構(gòu)造函數(shù)。
function SuperType(){ this.nums=[1,2]; } function SubType() { SuperType.call(this); } SubType.prototype=new SubType(); var instance=new SubType(); instance.nums.push(3); console.log(instance.nums); var instance2=new SubType(); console.log(instance2.nums);
通過使用call()方法(或apply()方法),在新創(chuàng)建的SubType實例的環(huán)境下調(diào)用了SuperType構(gòu)造函數(shù)。這樣就會在新SubType對象上執(zhí)行SuperType函數(shù)中定義的所有對象初始化代碼。SubType的每個實例都會具有自己的nums屬性的副本。
1.傳遞參數(shù)
子類型構(gòu)造函數(shù)向超類型構(gòu)造函數(shù)傳遞參數(shù)。
function SuperType(name){ this.name=name; this.school=["whu"]; } function SubType() { SuperType.call(this,"張三"); //實例屬性 this.age=20; } var instance=new SubType(); instance.school.push("hhu"); console.log(instance.name); console.log(instance.age); console.log(instance.school); var instance2=new SubType(); console.log(instance2.school);
2.存在的問題
方法都在構(gòu)造函數(shù)中定義,函數(shù)無法復(fù)用;
在超類型的原型中定義的方法,對于子類型而言是不可見的,那么所有類型都只能使用構(gòu)造函數(shù)模式。
使用原型鏈實現(xiàn)對原型屬性和方法的繼承,而通過構(gòu)造函數(shù)來實現(xiàn)實例屬性的繼承。
function SuperType(name){ this.name=name; this.city=["武漢","杭州"]; } 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("chen",18); instance1.city.push("北京"); console.log(instance1.city); instance1.sayName(); instance1.sayAge(); var instance2=new SubType("huang",19); console.log(instance2.city); instance2.sayName(); instance2.sayAge();原型式繼承
function object(o){ function F(){} F.prototype=o; return new F(); }
在object函數(shù)內(nèi)部,先創(chuàng)建一個臨時性的構(gòu)造函數(shù),然后將傳入對象作為這個構(gòu)造函數(shù)的原型,最后返回了這個臨時類型的一個新實例。本質(zhì)上是object()對傳入其中的對象執(zhí)行了一次淺復(fù)制。
var navy={ name:"海軍", weapon:["航母","驅(qū)逐艦"] }; function object(o){ function F() { } F.prototype=o; return new F(); } var navy1=object(navy); navy1.name="俄羅斯"; navy1.weapon.push("巡洋艦"); var navy2=object(navy); navy2.name="美國"; navy2.weapon.push("護衛(wèi)艦"); console.log(navy.weapon);
ECMAScript5新增Object.create()方法規(guī)范了原型式繼承,接收兩個參數(shù):一個是作用于新對象原型的對象,(可選)二是一個新對象定義額外屬性的對象.
var car={ name:"奔馳", weapon:["車輪","發(fā)動機"] }; var car1=Object.create(car,{ name:{ value:"寶馬" } }); console.log(car1.name);
原型式的問題依然是包含引用類型的屬性會所有實例被共享
寄生式繼承function object(o){ function F() { } F.prototype=o; return new F(); } function createAnother(original) { var clone=object(original); //通過調(diào)用函數(shù)創(chuàng)建一個新對象 clone.sayHi=function () { //以某種方式增強這個對象 console.log("hi"); }; return clone; //返回對象 } var person={ name:"coder", ability:["Java","R"] }; var another=createAnother(person); another.sayHi();
寄生式的問題依然是不能做到函數(shù)復(fù)用
寄生組合式繼承組合繼承最大的問題就是會調(diào)用兩次超類型構(gòu)造函數(shù):一次是創(chuàng)建子類型原型時候,一次是在子類型構(gòu)造函數(shù)內(nèi)部。
function SuperType(name){ this.name=name; this.city=["南京","蘇州"]; } SuperType.prototype.sayName=function () { console.log(this.name); } function SubType(name,age) { SuperType.call(this,name);//第二次調(diào)用SuperType this.age=age; } SubType.prototype=new SuperType(); //第一次調(diào)用SuperType SubType.prototype.constructor=SubType; SubType.prototype.sayAge=function () { console.log(this.age); }
在第一次調(diào)用SuperType構(gòu)造函數(shù)時,SubType.prototype會得到兩個屬性:name和colors;都是SuperType的實例屬性,只不過現(xiàn)在位于SubType的原型中.當(dāng)調(diào)用SubType構(gòu)造函數(shù),又會調(diào)用一次SuperType的構(gòu)造函數(shù),這一次又在新對象上創(chuàng)建了實例屬性name和colors.于是這兩個屬性就屏蔽了原型中的兩個同名屬性.
寄生組合式繼承通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混成形式來繼承方法.其基本思想是:不必為了指定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù),所需要的只是超類型原型的一個副本.本質(zhì)上,就是使用寄生式繼承來繼承超類型的原型,然后再講結(jié)果指定給子類型的原型.
function inheritPrototype(subType,superType){ var prototype=object(superType.prototype); //創(chuàng)建對象 prototype.constructor=subType; //增強對象 subType.prototype=prototype; //指定對象 }
inheritPrototype函數(shù)接受兩個參數(shù):子類型構(gòu)造函數(shù)、超類型構(gòu)造函數(shù)
1.創(chuàng)建超類型原型的一個副本
2.為創(chuàng)建的副本添加constructor屬性,彌補因重寫原型而失去的默認的constructor屬性.
3.將新創(chuàng)建的對象(即副本)賦值給子類型的原型.
function SuperType(name){ this.name=name; this.city=["南京","蘇州"]; } SuperType.prototype.sayName=function () { console.log(this.name); } function SubType(name,age) { SuperType.call(this,name);//第二次調(diào)用SuperType this.age=age; } inheritPrototype(SubType,SubType); SubType.prototype.sayAge=function () { console.log(this.age); }
上述只調(diào)用了一次SuperType構(gòu)造函數(shù),并因此避免了在SubType.ptototype上創(chuàng)建不必要的、多余的屬性.與此同時,原型鏈還能保持不變.
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/93627.html
摘要:可以通過構(gòu)造函數(shù)和原型的方式模擬實現(xiàn)類的功能。原型式繼承與類式繼承類式繼承是在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型的構(gòu)造函數(shù)。寄生式繼承這種繼承方式是把原型式工廠模式結(jié)合起來,目的是為了封裝創(chuàng)建的過程。 js繼承的概念 js里常用的如下兩種繼承方式: 原型鏈繼承(對象間的繼承) 類式繼承(構(gòu)造函數(shù)間的繼承) 由于js不像java那樣是真正面向?qū)ο蟮恼Z言,js是基于對象的,它沒有類的概念。...
摘要:首先為了模擬類創(chuàng)建對象的功能搞出了構(gòu)造函數(shù)。也就是名字膚色膚色這里是繼承里的自有屬性生命值這里繼承的共有屬性的方法攻擊力兵種美國大兵攻擊防御死亡膚色 JS面向?qū)ο笾?【繼承】 我們已經(jīng)準備了很多前置知識,包括 原型鏈,對象和對象之間的關(guān)系 this,對象和函數(shù)之間的關(guān)系 new, 用函數(shù)批量創(chuàng)建特定的對象的語法糖 JS面向?qū)ο蟮那笆澜裆?我們說,面向?qū)ο笫且环N寫代碼的套路。因為如...
摘要:對象創(chuàng)建的三種方式字面量創(chuàng)建方式系統(tǒng)內(nèi)置構(gòu)造函數(shù)方式自定義構(gòu)造函數(shù)構(gòu)造函數(shù)原型實例之間的關(guān)系實例是由構(gòu)造函數(shù)實例化創(chuàng)建的,每個函數(shù)在被創(chuàng)建的時候,都會默認有一個對象。 JS 對象創(chuàng)建的三種方式 //字面量創(chuàng)建方式 var person= { name:jack?。? //系統(tǒng)內(nèi)置構(gòu)造函數(shù)方式 var person= new Object(); person.name = jack; ...
閱讀 865·2023-04-26 00:30
閱讀 2780·2021-11-23 09:51
閱讀 1118·2021-11-02 14:38
閱讀 2775·2021-09-07 10:23
閱讀 2333·2021-08-21 14:09
閱讀 1538·2019-08-30 10:57
閱讀 1666·2019-08-29 11:20
閱讀 1208·2019-08-26 13:53