來源: 一米八的耗子 發(fā)布時(shí)間:2019-04-26 15:52:55 閱讀量:1686
有異議或者理解不對(duì)的地方歡迎指出
js繼承:通過某種方式讓一個(gè)對(duì)象可以訪問到另一個(gè)對(duì)象中的屬性和方法。
為什么使用繼承:
某些對(duì)象會(huì)有函數(shù)方法,如果把這些函數(shù)方法都放置在構(gòu)造函數(shù)內(nèi)部,會(huì)造成瀏覽器內(nèi)存的浪費(fèi)。
首先
先定義父類:
定義父類,并在父類的原型上添加方法
var p1=new Person();
var p2=new Person();
p1.printNamep2.printName–.true
p1.printName=p2.printName—true
如果比較的是對(duì)象的話,雙等和三等無區(qū)別。如果是值的話,雙等比較值是否一樣,三等還比較兩個(gè)值在是否指向?qū)σ粋€(gè)內(nèi)存。
**結(jié)論1:**根據(jù)上面的比較內(nèi)容可得知,只要在某個(gè)構(gòu)造函數(shù)的prototype屬性上添加屬性和方法,這個(gè)構(gòu)造函數(shù)的屬性和方法,都可以被該構(gòu)造函數(shù)的所有實(shí)例共享。
根據(jù)javascript權(quán)威指南中的解釋,這里的構(gòu)造函數(shù)的prototype對(duì)象稱之為原型對(duì)象
Person.prototypes是p1,p2(Person構(gòu)造函數(shù)實(shí)例)的原型對(duì)象
person的原型對(duì)象是function.prototype.
js的繼承方式有哪些
一:原型鏈繼承
子類實(shí)例的原型等于父類的實(shí)例,從而繼承父類構(gòu)造函數(shù)的屬性.構(gòu)造函數(shù)方法,原型方法,原型屬性.
但是原型屬性是子類共同使用的.如果修改了,其他子類會(huì)受到影響.另外實(shí)例無法向構(gòu)造函數(shù)傳參.
function PersonOne(){
}
PersonOne.prototype= new Person(“asd”,12);
var personone=new PersonOne(“sum1”);
personone.proto.proto.sex=“123”;
console.log(personone.name,personone.age);
console.log(personone.sex);
personone.setAge();
personone.printName();
console.log(personone,"&&&&");
var persontwo=new PersonOne();
console.log(persontwo.name,persontwo.age);
console.log(persontwo.sex)
persontwo.printName();
console.log(persontwo);
輸出:
想要避免這種情況,可以使用借用構(gòu)造函數(shù)實(shí)現(xiàn),也可以重新new新的子類去繼承父類
這樣除了父類原型屬性共享外,構(gòu)造參數(shù)實(shí)現(xiàn)了私有化.
二:借用構(gòu)造函數(shù)實(shí)現(xiàn)繼承
通過借助call/apply來改變this的指向,從而構(gòu)造獨(dú)有的作用域,每個(gè)實(shí)例繼承屬性私有化,相互之間不影響.
缺點(diǎn):構(gòu)造方法無法復(fù)用,每個(gè)實(shí)例有攜帶一個(gè)構(gòu)造方法.
function PersonOne(){
Person.call(this,arguments);
}
PersonOne.prototype= new Person();
var personone=new PersonOne(“tom”,“123”);
var persontwo=new PersonOne(“Jack”,“456”);
console.log(personone);
console.log(persontwo);
console.log(personone.setAge === persontwo.setAge)
console.log(personone.printName === persontwo.printName)
輸出:
三:組合繼承
把方法放到父類的原型上,實(shí)現(xiàn)復(fù)用.例如上述的printName方法,唯一不足的是父類構(gòu)造函數(shù)調(diào)用兩次,子類實(shí)例上會(huì)覆蓋子類原型上的.
四:原型繼承
通過在中間生成對(duì)象,使用中間對(duì)象去繼承父類,最后接收生成的新對(duì)象.
f
核心:
(1)function create(obj){
var F = function(){};
F.prototype = obj;
return new F();
}
用法:var person=new Person();
var proto=create(person);
不足:原型引用的屬性會(huì)被實(shí)例共享,而且無法實(shí)現(xiàn)復(fù)用.
五:寄生組合繼承
相對(duì)于來說較為完善.(Es6提供Object.create創(chuàng)造新對(duì)象的方法);
function Person(name,age){
this.name=name;
this.age=age;
this.setAge=function(){
console.log(this.age);
}
}
Person.prototype.printName=function(){
console.log(this.name);
}
Person.prototype.sex=“1”;
function PersonOne(){
Person.call(this,arguments);
}
//繼承父類原型上的屬性和方法,相比之前create去掉了多余的父類實(shí)例的屬性
var proto=Object.create(Person.prototype);
//將生成的proto新對(duì)象與PersonOne進(jìn)行關(guān)聯(lián),相當(dāng)于PersonOne實(shí)例化的實(shí)例.
proto.constructor=PersonOne;
//關(guān)聯(lián)原型,實(shí)例化后proto具有父類的構(gòu)造屬性,方法,原型的方法,屬性
PersonOne.prototype=proto;
自己在編寫的時(shí)候,發(fā)現(xiàn)這個(gè)問題.
function Person(){
this.name=“parent”
this.arr=[1,2];
}
Person.prototype.printName=function(){
console.log(this.name);
}
function PersonOne(){
}
PersonOne.prototype=new Person();
var person=new PersonOne();
person.name="2";
person.arr.push(4)
console.log(person)
var per2=new PersonOne();
console.log(per2)
name屬性在實(shí)例上實(shí)例化,但是arr卻并沒有實(shí)例化,原因在于arr為引用類型,在賦值的時(shí)候?qū)嵗龝?huì)隨著原型鏈找到arr的位置并修改值(arr在堆上的地址是唯一的).而name是String類型,所以不能直接修改值,需要通過實(shí)例化生成對(duì)象,從而修改值.每一個(gè)實(shí)例化的對(duì)象在棧上的位置不同,具有私有化.