通过原型链继承,以及引用数据出现问题

1. 原型链继承

通过原型链机制实现继承。如下代码所示:

<script>
    // 宠物构造函数
    function Pet(name){
        this.name = name || '无';
    }
    Pet.prototype.getName = function(){
        return this.name;
    };
    Pet.prototype.setName = function(name){
        this.name = name;
    };
    Pet.prototype.eat = function(){
        console.log('吃饭');
    };
    // 狗狗构造函数
    function Dog(name, strain){
        this.name = name;
        this.strain = strain || '中华田园犬';
    }
    // 让创建对象继承自宠物对象
    Dog.prototype = new Pet();
    Dog.prototype.constructor = Dog;
    Dog.prototype.getStrain = function(){
        return this.strain;
    };
    Dog.prototype.setStrain = function(strain){
        this.strain = strain;
    };
    // 覆盖原型方法
    Dog.prototype.eat = function(){
        console.log('吃狗粮');
    };

    // 测试
    var dog = new Dog('欢欢', '黑贝');
    console.log('名字:' + dog.getName());
    console.log('品种:' + dog.getStrain());
    dog.eat();
</script>

说明:以上示例中,似乎 Pet 构造函数的参数并没有什么用处,我们暂且不管,后面再解释。

2. 原型链的问题

继承中引用数据类型的问题 如果父类中除了基本数据类型外,还有引用数据类型,那么,原型继承可能出现问题。

<script>
        // 宠物构造函数
        function Pet(name){
            this.name = name || '无';
            this.hacks = ['叼飞盘', '拉雪橇'];
        }
        Pet.prototype.getName = function(){
            return this.name;
        };
        Pet.prototype.setName = function(name){
            this.name = name;
        };
        Pet.prototype.eat = function(){
            console.log('吃饭');
        };
        // 狗狗构造函数
        function Dog(name, strain){
            this.name = name;
            this.strain = strain || '中华田园犬';
        }
        // 让创建对象继承自宠物对象
        Dog.prototype = new Pet();
        Dog.prototype.constructor = Dog;
        Dog.prototype.getStrain = function(){
            return this.strain;
        };
        Dog.prototype.setStrain = function(strain){
            this.strain = strain;
        };
        // 覆盖原型方法
        Dog.prototype.eat = function(){
            console.log('吃狗粮');
        };

        // 测试
        var xx = new Dog('笑笑', '牧羊犬');
        xx.hacks.push('看羊群');
        console.log('名字:' + xx.getName());
        console.log('品种:' + xx.getStrain());
        console.log(xx.hacks);
        console.log();
        var hh = new Dog('欢欢', '黑贝');
        console.log('名字:' + hh.getName());
        console.log('品种:' + hh.getStrain());
        console.log(hh.hacks);
</script>

说明:我们看到笑笑向 hacks 添加了 '看羊群' 技能,在欢欢中也看到了,这不是我们的本意,我们本意是想,各只狗狗都有自己的技能。 这是因为 Dog 原型对象的属性 hacks 是引用类型,只创建了一个对象,所有的狗狗对象都指向同一原型中的 hacks 属性。应该为每个狗狗创建自己的 hacks 数组。

3. 组合继承

使用构造函数借用解决引用数据类型的问题。

<script>
    // 宠物构造函数
    function Pet(name){
        this.name = name || '无';
        this.hacks = ['叼飞盘', '拉雪橇'];
    }
    Pet.prototype.getName = function(){
        return this.name;
    };
    Pet.prototype.setName = function(name){
        this.name = name;
    };
    Pet.prototype.eat = function(){
        console.log('吃饭');
    };
    // 狗狗构造函数
    function Dog(name, strain){
        Pet.call(this, name);  // !!!替换 this.name = name;
        this.strain = strain || '中华田园犬';
    }
    // 让创建对象继承自宠物对象
    Dog.prototype = new Pet();
    Dog.prototype.constructor = Dog;
    Dog.prototype.getStrain = function(){
        return this.strain;
    };
    Dog.prototype.setStrain = function(strain){
        this.strain = strain;
    };
    // 覆盖原型方法
    Dog.prototype.eat = function(){
        console.log('吃狗粮');
    };

    // 测试
    var xx = new Dog('笑笑', '牧羊犬');
    xx.hacks.push('看羊群');
    console.log('名字:' + xx.getName());
    console.log('品种:' + xx.getStrain());
    console.log(xx.hacks);
    console.log();
    var hh = new Dog('欢欢', '黑贝');
    console.log('名字:' + hh.getName());
    console.log('品种:' + hh.getStrain());
    console.log(hh.hacks);
</script>

说明:

  1. 我们只修改了一句代码,将 this.name = name; 替换为 Pet.call(name);

  2. 这种方式叫做构造函数借用。我们借用 Pet 构造函数,在构造新 Dog 时,在当前对象上单独创建一个 hacks 数组;

  3. 同时,也能将 name 赋值在当前对象上,所以,能够完全替换原来的赋值代码。

  4. 以上这种利用了原型链,同时使用了构造函数借用的继承方式,我们称为组合继承。

4. ES6 中新的原型继承的方式

<script>
  // 3. ES6 新的 原型继承的方式,无需借助函数
  var parent = {name : '无名'};
  var son = new Object(parent);
  son.age = 18;
  console.log('son.name = ' + son.name);
  console.log('son.age = ' + son.age);
</script>

  • 25
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值