这种Javascript继承方法有问题吗?

时间:2014-05-01 16:56:17

标签: javascript inheritance

我希望用JavaScript做一些继承,在搜索内部网时,我发现了许多示例和多种方式和继承实现。我最终找到了一个我喜欢的,因为它的简单性和所有阅读和学习我想出了这种方法:

var Animal = function () {
    var self = this;
    self.legs = 4;
    self.makeNoise = function () {
        return "noise";
    };
};

var Dog = function () {
    var self = new Animal();
    self.base = {
        makeNoise: self.makeNoise
    };

    self.makeNoise = function () {
        var noise = "bark \n";
        noise += self.base.makeNoise();

        return noise;
    };

    return self;
};

var Monkey = function () {
    var self = new Animal();
    self.base = {
        makeNoise: self.makeNoise
    };
    self.legs = 2;
    self.makeNoise = function () {
        var noise = "weird monkey sound \n";
        noise += self.base.makeNoise();

        return noise;
    };

    return self;
};

$("#monkey").click(function () {
    var monkey = new Monkey();
    var result = "Legs: " + monkey.legs + "\n";
    result += "Noise: " + monkey.makeNoise();
    alert(result);
});

$("#dog").click(function () {
    var dog = new Dog();
    var result = "Legs: " + dog.legs + "\n";
    result += "Noise: " + dog.makeNoise();
    alert(result);
});

你可以找到一个有效的JSFiddle here

从代码中可以看出,我在base变量中保留了对原始基函数的引用,因此我可以调用base。你觉得这种方法有什么问题吗?任何缺点,监督未来可能出现的问题,我缺少什么?

3 个答案:

答案 0 :(得分:2)

嗯,这有一件事是错的:

var dog = new Dog();
console.log(dog instanceof Dog) //=> false

问题是,你所做的实际上是不是继承。您只是使用函数来返回动物对象的修改版本。这导致一种类似于继承的行为,但不是一回事。

JavaScript的对象模型使用称为原型链的东西,它与典型的面向对象的继承非常相似。 Mozilla开发者网络有一篇很好的文章:Inheritance and the prototype chain

以下是您在示例中如何使用原型继承的示例:

var Animal = function() {};
Animal.prototype = {
    legs: 4,
    makeNoise: function () {
        return "noise";
    }
};

var Dog = function () {};
// Notice: Dog.prototype is inheriting from Animal.prototype
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.makeNoise = function () {
    var noise = "bark \n";
    // Notice: calling Animal's makeNoise function with
    // 'this' set to our dog object.
    noise += Animal.prototype.makeNoise.call(this);

    return noise;
};

var Monkey = function () {};
// Notice: Monkey.prototype is inheriting from Animal.prototype
Monkey.prototype = Object.create(Animal.prototype)
Monkey.prototype.legs = 2;
Monkey.prototype.makeNoise = function () {
    var noise = "weird monkey sound \n";
    // Notice: calling Animal's makeNoise function with
    // 'this' set to our monkey object.
    noise += Animal.prototype.makeNoise.call(this);

    return noise;
};

$("#monkey").click(function () {
    var monkey = new Monkey();
    var result = "Legs: " + monkey.legs + "\n";
    result += "Noise: " + monkey.makeNoise();
    alert(result);
});

$("#dog").click(function () {
    var dog = new Dog();
    var result = "Legs: " + dog.legs + "\n";
    result += "Noise: " + dog.makeNoise();
    alert(result);
});

$("#inheritance").click(function () {
    var dog = new Dog();
    var monkey = new Monkey();
    var result = 'dog instanceof Dog = ' + (dog instanceof Dog) + "\n" +
        'dog instanceof Animal = ' + (dog instanceof Animal) + "\n" +
        'dog instanceof Monkey = ' + (dog instanceof Monkey) + "\n" +
        'monkey instanceof Monkey = ' + (monkey instanceof Monkey) + "\n" +
        'monkey instanceof Animal = ' + (monkey instanceof Animal) + "\n" +
        'monkey instanceof Dog = ' + (monkey instanceof Dog) + "\n";
    alert(result);
});

View JS Fiddle

答案 1 :(得分:1)

除了通过返回self打破继承链之外,您可能对JavaScript的继承技术产生了误解:

JavaScript是一种基于原型的语言,意味着正确的继承设置如下:

function Animal(){}

Animal.prototype.walk = function(){
    console.log('walking...');
};

Animal.prototype.roar = function(){
    alert('roar');
};

function Dog(){}

Dog.prototype = new Animal();

Dog.prototype.roar = function(){
    alert('bark!');
};

var animal = new Animal();
var dog = new Dog();

animal.walk();
dog.walk();   // both can call the walk function

animal.roar(); // alerts roar
dog.roar(); // alerts bark

Prototypal继承允许对象定义的共享内存(将对象记录到控制台以查看我的意思)。换句话说,Dog的每个实例都将使用相同的roar函数,但通过将属性直接附加到构造函数中的this,您将阻止原型链并委托函数的内存到该对象的每个实例。如果您要创建该对象的许多实例,则应用程序的性能将反映这一点。

@Thom在我的例子中展示了经典继承与原型。要么是正确的,但这是一个很好的Stack answer about this

答案 2 :(得分:1)

这是一篇优秀的文章:http://javascriptissexy.com/oop-in-javascript-what-you-need-to-know/

//Constructor/Object
function Animal(inNoise) {
    this.legs = 4;
    this.noise = inNoise;
}

//Set Objects prototypes
Animal.prototype = {
    constructor: Animal,
    changeNoise: function(newNoise){this.noise = newNoise;}
}

//Create some dogs
var dog = new Animal('bark');
var pitbull = Object.create(dog);
var chiahua = Object.create(dog);

//Change dogs noise
chiahua.changeNoise('littleBark');

alert(dog.noise); //bark
alert(pitbull.noise);//bark
alert(chiahua.noise); //littlebark
alert(chiahua.legs); //4