您的位置:首页 > Web前端 > JavaScript

几种继承模式的比较

2016-06-15 16:03 513 查看

一、 默认模式

function Parent(){
this.nameArr=["name0","name1","name2"];
}
Parent.prototype.sayName = function() {
console.log(this.nameArr);
};
function Child1(){};
Child1.prototype = new Parent();
var child1_1=new Child1();
var child1_2=new Child1();
console.log(child1_1.nameArr);
console.log(child1_2.nameArr);
child1_2.nameArr.push("name3");
console.log(child1_1.nameArr);
console.log(child1_2.nameArr);
console.table(child1_1);
console.table(child1_2);




因为在Child1的构造函数的原型上继承的Parent实例,又因为
child1_1
child1_2
共享原型,故
child1_1
child1_2
的原型都指向了这个Parent实例。所以只是引用继承。所以在
child1_2.nameArr.push("name3");
操作后,会导致
child1_1.nameArr
里也出现
name3


并且采用new操作符,将继承Parent的所有公共属性(被this引用,可供外部使用点操作或中括号操作访问的属性)和原型

这里顺便提一下new操作都做了些什么

1、创建了一个新对象,并用this对其进行引用,同时使其继承原函数的原型。

2、将原函数内部使用this引用的属性和方法添加到新对象。

3、返回this.

function Parent(){
var someWords="hello!";
this.nameArr=["name0","name1","name2"];
}
Parent.prototype.sayName = function() {
console.log(this.nameArr);
};
Parent.prototype.sex="famle"
var child1_1=new Parent();
var child1_2=new Parent();
console.log(child1_1.nameArr);
console.log(child1_2.nameArr);
child1_2.nameArr.push("name3");
console.log(child1_1.nameArr);
console.log(child1_2.nameArr);
console.table(child1_1);
console.table(child1_2);




二、借用构造函数模式

function Parent(str){
this.name=str||"Liz";
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child1 (str) {
Parent.apply(this,[str]);
this.sex="female";
};
function Child2 (str) {
Parent.apply(this,[str]);
this.sex="male";
};
var child1=new Child2("Liz");
var child2=new Child2("Cyt");
console.log(child1.name);


通过applycall方法,我们可以继承到Parent的属性,而且获得的是副本。apply和call并不能继承Parent的原型,所以还得继续设置。



三、借用和设置原型

function Parent() {
this.name = "Xzz";
}
Parent.prototype.age="21";
Parent.prototype.sayName = function() {
return this.name;
};

function Child1(s1,s2){
Parent.apply(this);
this.sex=s2||'female';
};
function Child2(s1,s2){
Parent.apply(this);
this.sex=s2||'male';
this.name="Lucy";
};
Child1.prototype=new Parent();
Child2.prototype=new Parent();
Child2.prototype.age="22";

var child1=new Child1("Liz");
var child2=new Child2("Cyt");

console.log(child1.name);
console.log(child1.age);
console.log(child1);

console.log(child2.name);
console.log(child2.age);
console.log(child2);


通过applycall方法继承Parent的属性获得的是独立的副本。为了弥补apply和call并不能继承Parent的原型的缺点,再次使用了new操作符在Child1的构造函数的原型上继承的Parent。这样做确实获得了独立的属性和共用的原型,但是属性我们继承了两次,有些累赘了,那就继续优化吧。



四、共享原型

function Parent() {
this.name = "Xzz";
}
Parent.prototype.age="21";
Parent.prototype.sayName = function() {
return this.name;
};

function Child1(s1,s2){
Parent.apply(this);
this.sex=s2||'female';
};
function Child2(s1,s2){
Parent.apply(this);
this.sex=s2||'male';
this.name="Lucy";
};
Child1.prototype=Parent.prototype;
Child2.prototype=Parent.prototype;
//Child2.prototype.age="22";

var child1=new Child1("Liz");
var child2=new Child2("Cyt");

console.log(child1.name);
console.log(child1.age);
console.log(child1);

console.log(child2.name);
console.log(child2.age);
console.log(child2);


applycall方法继承Parent的属性获得的是独立的副本

使用子孙实例与祖先共享原型确实实现了,独立副本共用原型的效果,但是问题又来了,这样我们在操作子孙元素的Prototype属性时很容易误覆盖了祖先的原型···太不安全了···继续改进,我们需要到达祖先原型的桥梁,但是我们不能让他太容易就到达···毕竟我们在子孙对象上操作时,最多操作子孙的原型。



五、临时构造函数

function Parent(str) {
this.name = str||"Xzz";
}
Parent.prototype.age="21";
Parent.prototype.sayName = function() {
return this.name;
};

function Child1(s1,s2){
Parent.apply(this,[s1]);
this.sex=s2||'female';
};
function Child2(s1,s2){
Parent.apply(this,[s1]);
this.sex=s2||'male';
};
var Func=function (){};
Func.prototype=Parent.prototype;
Child1.prototype=new Func();
Child2.prototype=new Func();
Child2.prototype.age="22";

Parent.prototype.constructor=Parent;
Child1.prototype.constructor=Child1;
Child2.prototype.constructor=Child2;

var child1=new Child1("Liz");
var child2=new Child2("Cyt");

console.log(child1.name);
console.log(child1.age);
console.log(child1);

console.log(child2.name);
console.log(child2.age);
console.log(child2);


在Parent对象与Child对象间采用空Func()作为原型链纽带,使我们可以找到Parent的原型,在操作Child.prototype时也只是影响到了空Func(),对Parent的原型不会造成影响,除非你故意要越过Func。为了避免constructor的怪异表现,在修改原型指向后要记得将各自的构造函数正确指定。



小计

一些杂七杂八的话。

prototype是函数独有的属性。

__proto__
是实际对象的属性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  继承 javascript