JavaScript对象继承 - 我做错了什么?

时间:2011-01-24 22:56:15

标签: javascript object

这段代码有什么问题?有人可以帮助我使用JavaScript Object Inheritance吗?我开始觉得自己像个白痴!!

提前致谢, 萨姆

function Human(name, sex) {
    this.name = name;
    this.sex = sex;
};

function Man(name) {
    Man.prototype = new Human(name, "Male");
};

var m = new Man("Sam Striano");
alert(m.name); //<-- = Undefined

5 个答案:

答案 0 :(得分:2)

你想要这个:

function Man(name) {
    Human.call(this, name, "Male");
}

该代码的作用

看起来你只是试图调用父Human的构造函数,这与原型继承不同。上面的代码采用Human的构造函数并将其应用于this - 一个新的Man对象。

您的代码的作用

每次创建新人时,Man.prototype = new Human(name, "Male")行都会更改Man 的原型 。不仅如此,您正在完成重新分配原型对象,因此它仅适用于 之后创建的对象 - 即不是第一个。因此,m.name未定义。

适当的原型继承

请注意,调用父的构造函数,如上面的代码所示,不会导致Man自动继承分配给Human.prototype的任何方法。执行此操作的最佳方法是将Human.prototype克隆到Man.prototype中,但不在任何构造函数之外。像这样:

function Man(name) {
    Human.call(this, name, "Male");
}

function inherit(parent, child) {
    if (Object.create) child.prototype = Object.create(parent.prototype);
    else {
        for (var key in parent.prototype) {
            if (!parent.prototype.hasOwnProperty(key)) continue;
            child.prototype[key] = parent.prototype[key];
        }
    }
}

inherit(Human, Man);

这可能看起来相当冗长,另一种方法可能就是这样做:

Man.prototype = new Human('no name', 'Male');

哪个会起作用,但会导致不必要的副作用,因为我们被迫为prototype分配了一个dud名称,并让Human的构造函数调用分配原型的额外时间。如果您沿着此路径走,并稍后更改Human构造函数,而不仅仅将属性分配给this,请收到警告。

答案 1 :(得分:1)

在javascript中通常有两个模仿经典继承的步骤:

  1. 您的子类构造函数需要调用父构造函数

  2. 您的子类原型需要链接到父原型

  3. 第一步通常看起来像

    function Subclass(blah) {
        ParentClass.apply(this, arguments);
    }
    

    第二步比较棘手。在实现__proto__属性的JS环境中,您可以执行

    Subclass.prototype = {
        __proto__ : ParentClass.prototype,
        subclassMethod1: function() { /* ... */ }
    }
    

    除非您确切知道脚本的运行位置(例如在node.js环境中),否则您不能依赖__proto__可用于您的脚本,因此一般方法需要使用{{3 }}:

    if (typeof Object.create !== 'function') {
        Object.create = function (o) {
            function F() {}
            F.prototype = o;
            return new F();
        };
    }
    Subclass.prototype = Object.create(ParentClass.prototype);
    Subclass.prototype.subclassMethod1 = function() { /* ... */ }
    

    这就是它的要点。 ES5运行时可能已经内置了Object.create(),这很好。

    有一些剩余的东西可以完成经典继承的幻觉,比如能够轻松调用父类的覆盖方法。有了我们现在所拥有的,你需要在你的Subclass方法中有类似ParentClass.prototype.overridenMethod.call(this, arg1, arg2)的东西。 一些OO库将有助于在每个子类实例上定义额外的内容,以便您可以使用this.superclass.overridenMethod(arg1, arg2)之类的内容。

    这种残酷的实施留给了读者一个练习;)

答案 2 :(得分:1)

我认为你所追求的是在Man的继承属性中拥有Human类。您已走上正轨,但需要将新Human实例作为Man的原型对象应用一次。

function Human(name, sex) {
    this.name = "some default";
    this.sex = sex;
};

function Man(name) {
    if( name !== undefined )
        this.name = name;
};
Man.prototype = new Human(name, "Male");
Man.prototype.constructor = Man;

var m = new Man("Sam Striano");

alert(m.name);  // alerts "Sam Striano"
alert(m.sex);   // alerts "Male"

答案 3 :(得分:1)

据我所知,您应该使用prototypeconstructor来处理所有内容,并且可以通过这种方式管理inerithance:


// Define superclass      
function Human( name, sex ) {
    this.name = name;
    this.sex = sex;
}                                 

// Define superclass methods      
Human.prototype.method1 = function() {
   alert( 'This is the call to ORIGINAL method1() with name: ' + this.name + ' and sex: ' + this.sex );
}

// Define subclass      
function Man( name, age ) {                                        
    this.constructor.apply( this, [ name, 'Man' ] );
    this.age = age;
}      

// Define subclass inerithance
Man.prototype = new Human();

// Define subclass methods
Man.prototype.method1 = function() {
    alert( 'This is the call to OVERWRITE method1() with name: ' + this.name + ' and sex: ' + this.sex + ' and age: ' + this.age );
    this.constructor.prototype.method1.apply( this );
}

var m = new Man( 'Sam Satriano', 30 );
m.method1();
// Should alert:
// This is the call to OVERWRITE method1() with name: Sam Satriano and sex: Man and age: 30
// This is the call to ORIGINAL method1() with name: Sam Satriano and sex: Man

希望这会有所帮助。侨!

答案 4 :(得分:1)

如果不进行继承斗争,可以通过将代码更改为以下内容来解决问题:

function Human(name, sex) {
    this.name = name;
    this.sex = sex;
};

function Man(name) {
    // This is how you call the parent's constructor
    Human.call(this, name, "Male");
};

// The call to setup the prototype only needs to happen once
// Not in every instantiation of the object
Man.prototype = new Human();
// Have to fix the constructor, right now it's set to Human
Man.prototype.constructor = Man;

var m = new Man("Sam Striano");
>> m.name // outputs "Sam Striano";
>> m instanceof Human // outputs true

这仍然不是一种理想的继承方式。我发布了一些解释什么是良好的JS继承的东西。 http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html