JavaScript学习-面向对象与原型5

版权声明:本文为博主原创文章,欢迎转载。 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);// 对象冒充 }

猜你喜欢

转载自blog.csdn.net/fww330666557/article/details/78772280