原型链实现继承的疑问?

以下是我的尝试过程

First

function Parent() {
    this.count = 1;
    this.addCount = function() {
        console.log(++this.count);
    };
    this.items = [];
    this.addItem = function(item) {
        this.items.push(item);
        console.log(this.items);
    };
}

function Child() {
}

Child.prototype = new Parent();

var child1 = new Child();
var child2 = new Child();

child1.addCount(); // 2
child2.addCount(); // 2
child1.addItem('child1'); // child1
child2.addItem('child2'); // child1, child2

console.log(child1);
/*
    count: 2
    __proto__: Parent
        count: 1
        items: ['child1', 'child2']
        addCount: function
        addItem: function
    
*/

Result

发现有个问题,引用属性共享了

Try agian

// 忽略未修改的代码
function Child() {
    Parent.call(this); // 显示调用父类的构造函数
}
console.log(child1);
/*
    count: 2
    items: ['child1']
    addCount: function
    addItem: function
    __proto__: Parent
        count: 1
        items: []
        addCount: function
        addItem: function
    
*/

Result

重复定义了addCount和addItem方法

Try again

// 忽略未修改的代码
function Parent() {
    this.count = 1;
    this.items = [];
}

Parent.prototype.addCount = function() {
    console.log(++this.count);
};

Parent.prototype.addItem = function(item) {
    this.items.push(item);
    console.log(this.items);
};
console.log(child1);
/*
    count: 2
    items: ['child1']
    __proto__: Parent
        count: 1
        items: []
        addCount: function
        addItem: function
    
*/

Result

从结果上看简单实现了继承,但是有几个疑问:

  1. Object.create or new
  2. 如何实现非引用类型属性的共享
  3. 显式调用父类的构造函数感觉很繁琐,看能不能去掉
  4. 多重继承?

大家是怎么使用原型链实现继承的呢?

--------------- 2018/1/18 13:45 ------------------------

看了@Maxiye提供的文章,也许可以使用简单的混合实现,类似于php的trait,针对某些情况可能比较适用

// 去掉原型链关联
// Child.prototype = new Parent();

function Child() {
    Parent.call(this);
}
阅读 1.7k
2 个回答

解释一下"First" 的输出结果。

function Parent() {
    this.count = 1;
    this.addCount = function() {
        console.log(++this.count);
    };
    this.items = [];
    this.addItem = function(item) {
        this.items.push(item);
        console.log(this.items);
    };
}

function Child() {
}

Child.prototype = new Parent();

var child1 = new Child();
var child2 = new Child();

child1.addCount(); // 2
child2.addCount(); // 2
child1.addItem('child1'); // child1
child2.addItem('child2'); // child1, child2

你这个代码的问题不是不能继承。其实child1 和child2 都继承了Parent 的property.

var child1 = new Child(); // child1 : {} initial 了一个空的child1, 它的__.proto__ 是 new Parent()
var child2 = new Child(); // child2 : {} initial 了一个空的child2, 它的__.proto__ 是 new Parent()
child1.addCount(); // child1: {count: 2} 调用child1的addCount(), 没有这个函数,找原型链, 找到, 这时候 addCount() 中的this 指向的是child1, 所以++this.count 相当于:this.count = this.count + 1, 相当于一个赋值: child1.count = 2;
child2.addCount(); // child2: {count: 2} 原理同上
child1.addItem('child1'); // child1: {count: 2} 调用 child1中的addItem(),没有这个函数,找原型链,找到。 这时候addItem()中的this 指向的也是child1, 但是child1 没有items这个property,不能push,所以只能找原型链中的items,找到。所以这个push ,就是对原型链里面的items.push(child1).
child2.addItem('child2'); // child2: {count: 2} 调用 child2中的addItem(),没有这个函数,找原型链,找到。 这时候addItem()中的this 指向的也是child2, 但是child2 没有items这个property,所以只能找原型链,找到。所以这个push ,就是对原型链里面的items.push(child2), 所以原型链里面的items 就是[child1, child2].

加一行代码就能实现你想要的继承:

function Parent() {
    this.count = 1;
    this.addCount = function() {
        console.log(++this.count);
    };
    this.items = [];
    this.addItem = function(item) { 
        this.items=[];//加了这一行,每一个调用addItem的child,都给它initial 一个items 
        this.items.push(item);
        console.log(this.items);
    };
}

function Child() {
}

Child.prototype = new Parent();

var child1 = new Child();
var child2 = new Child();

child1.addCount(); // 2
child2.addCount(); // 2
child1.addItem('child1'); // child1
child2.addItem('child2'); // child2
推荐问题
宣传栏