版权声明:本文为博主原创文章,欢迎转载。 https://blog.csdn.net/fww330666557/article/details/78772280
继承
JS支持继承。
通过原型链实现继承
function Box(){
this.name = 'Lee';
}
function Desk(){
this.page = 100;
}
Desk.prototype = new Box();
测试代码:
var desk = new Desk();
document.write(desk.name);
测试输出:
Lee
可以看到,Desk继承了Box的属性name。
就近原则
那么,如果Box的原型中,也有一个name属性,输出的将会是什么呢?
测试代码:
Box.prototype.name = 'Jack';
var desk = new Desk();
document.write(desk.name);
测试输出:
Lee
可以看到输出并没有改变。那么这里也符合就近原则,实例里有就返回,没有就去原型中找。
从属关系
所有的构造函数都继承自Object,而继承Object是自动完成,不需要手动继承。子类型从属自己或它的超类型。
测试代码:
var desk = new Desk();
document.write(desk instanceof Object);
document.write("<br/>")
document.write(desk instanceof Box);
document.write("<br/>")
document.write(desk instanceof Desk);
测试输出:
true
true
true
通过对象冒充继承
通过原型链继承存在引用共享和超类型无法传参的问题,为了解决这些问题,我们可以使用对象冒充继承。
function Box(name,age){
this.name = name;
this.age = age;
}
function Desk(name, age){
Box.call(this,name,age);// 对象冒充只能继承构造里的信息,不能继承原型里的信息
}
测试代码:
Box.prototype.family = '家庭';
var desk = new Desk('Lee',100);
document.write(desk.name);
document.write("<br/>")
document.write(desk.family);
document.write("<br/>")
document.write(desk instanceof Object);
document.write("<br/>")
document.write(desk instanceof Box);
document.write("<br/>")
document.write(desk instanceof Desk);
测试结果:
Lee
undefined //对象冒充只能继承构造里的信息,不能继承原型里的信息
true
false// desk不是Box的实例
true
组合继承
单独使用原型继承和对象冒充继承度存在明显的缺陷,所以我们将二者组合起来使用,就是组合继承。
function Box(name,age){
this.name = name;
this.age = age;
}
function Desk(name, age){
Box.call(this,name,age);// 对象冒充继承
}
Desk.prototype = new Box();// 原型链继承
测试代码:
Box.prototype.family = '家庭';
var desk = new Desk('Lee',100);
document.write(desk.name);
document.write("<br/>")
document.write(desk.family);
document.write("<br/>")
document.write(desk instanceof Object);
document.write("<br/>")
document.write(desk instanceof Box);
document.write("<br/>")
document.write(desk instanceof Desk);
测试输出:
Lee
家庭
true
true
true
一切都符合预期,构造函数中的数据和原型中的数据都被继承了。组合继承应用非常广泛。
原型式继承
// 临时中转函数
function obj(o){
function F(){}
F.prototype = o;
return new F();
}
var box = {
name :'Lee',
age :100,
family:['哥哥','姐姐','妹妹']
}
测试代码:
var box1 = obj(box);
document.write(box1.name);
document.write("<br/>")
document.write(box1.family);
document.write("<br/>")
box1.family.push('弟弟');
document.write(box1.family);
document.write("<br/>")
var box2 = obj(box);
document.write(box1.family);
测试结果:
Lee
哥哥,姐姐,妹妹
哥哥,姐姐,妹妹,弟弟
哥哥,姐姐,妹妹,弟弟// 引用类型的属性共享了
可见原型式继承跟原型链继承的本质是一样的,只是写法不一样。
寄生式继承
寄生式继承 = 原型式 + 工厂模式。
// 临时中转函数
function obj(o){
function F(){}
F.prototype = o;
return new F();
}
// 寄生函数
function create(o){
var f = obj(o);
f.run = function(){
return this.name + '来自方法!';
}
return f;
}
var box = {
name :'Lee',
age :100,
family:['哥哥','姐姐','妹妹']
}
var box1 = create(box);
document.write(box1.name);
document.write("<br/>")
document.write(box1.run());
测试结果:
Lee
Lee来自方法!
寄生组合继承
组合继承会调用两次Box:
function Box(name,age){
this.name = name;
this.age = age;
}
function Desk(name, age){
Box.call(this,name,age);// 第二次调用Box
}
Desk.prototype = new Box();// 第一次调用Box
寄生组合继承解决了两次调用的问题。
寄生组合继承:
// 临时中转函数
function obj(o){
function F(){}
F.prototype = o;
return new F();
}
// 寄生函数
function create(box,desk){
var f = obj(box.prototype);
f.constructor = desk;// 调整原型构造指针
desk.prototype = f;
}
function Box(name, age){
this.name = name;
this.age = age;
}
Box.prototype.run = function(){
return this.name + this.age + '运行中...';
}
function Desk(name,age){
Box.call(this,name,age);// 对象冒充
}
// 通过寄生组合继承来实现继承
create(Box,Desk);
测试代码:
var desk = new Desk('Lee',100);
document.write(desk.run());
document.write("<br/>")
document.write(desk.constructor);
测试结果:
Lee100运行中...
function Desk(name,age){ Box.call(this,name,age);// 对象冒充 }