以正确的方式定义原型属性

时间:2013-12-17 20:56:09

标签: javascript constructor prototype

我对如何定义原型属性有疑问。因此,您不必编写" MyClass.prototype。"为了将每个属性添加到原型,人们创建新对象并将其设置为原始对象。

喜欢这个。

var MyClass = function() {}

MyClass.prototype = {
    sayHi : function() {
        alert('hi');
    }
}

但是如果你这样做,当你试图从任何实例访问构造函数时,它可能会导致问题。

var o1 = new MyClass();

alert( o1 instanceof MyClass ); // true
alert( o1.constructor === MyClass ); // false !!!

o1.constructor通常指向MyClass,但由于原始原型已更改,因此不再适用。

我设法通过MyClass.prototype.constructor = MyClass;解决了这个问题,并且它再次正常工作。

问题是,还有哪些其他问题会改变原始原型?

如何定义原型属性?

4 个答案:

答案 0 :(得分:2)

我通常使用简单的defclass函数在JavaScript中创建“类”:

function defclass(prototype) {
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
}

这个函数允许我按如下方式创建类:

var MyClass = defclass({
    constructor: function () {},
    sayHi: function () {
        alert("hi");
    }
});

该方法具有以下优点:

  1. 所有原型属性都封装在一个对象文字中。
  2. constructor函数本身只是另一个原型属性。
  3. 实例将始终具有正确的constructor属性。
  4. 例如:

    var o1 = new MyClass;
    alert(o1 instanceof MyClass);      // true
    alert(o1.constructor === MyClass); // true
    

    您还可以轻松修改defclass以支持继承:

    function defclass(uber, body) {
        var base = uber.prototype;
        var prototype = Object.create(base);
        var constructor = body.call(prototype, base), prototype.constructor;
        constructor.prototype = prototype;
        return constructor;
    }
    

    然后您可以按如下方式使用它:

    var Rectangle = defclass(Object, function () {
        this.constructor = function (width, height) {
            this.height = height;
            this.width = width;
        };
    
        this.area = function () {
            return this.width * this.height;
        };
    });
    

    继承也很简单:

    var Square = defclass(Rectangle, function (base) {
        this.constructor = function (side) {
            base.constructor.call(this, side, side);
        };
    });
    

    一切都按预期工作:

    var sq = new Square(5);
    
    alert(sq.area());                 // 25
    alert(sq instanceof Square);      // true
    alert(sq instanceof Rectangle);   // true
    alert(sq.constructor === Square); // true
    

    那是所有人。

答案 1 :(得分:1)

您可以使用合并/扩展功能(常见于jQuery或Lodash等库中):

$.extend(MyClass.prototype, { prop: ..., ... });

答案 2 :(得分:1)

constructor属性只是一个方便的参考,你可以简单地重新分配它:

MyClass.prototype = {
    constructor: MyClass,
    sayHi : function() {
        alert('hi');
    }
}

重新定义原型对象不应该有任何其他“问题”,除非您正在使用预定义的原型属性扩展另一个对象。

如果您想要勇于学习语法,请尝试使用with。我不推荐它,但如果你只想缩短语法,它仍然是一个选项:

var MyClass = function() {}

with (MyClass.prototype) {
    sayHi = function() {
        alert('hi');
    }
}

答案 3 :(得分:1)

我通常选择:

function MyClass() {}

MyClass.prototype = {
    constructor: MyClass,

    foo: function foo() {
        // do something
    }
};

我意识到它覆盖了constructor属性,但是维护起来比较干净,在实践中我没有注意到10年来我一直在编写JavaScript"类和#34;这样。

也可以使用原生Object.create方法。

前段时间我创建了一个小型JavaScript库来帮助编写课程: Inherit.js

它允许您创建这样的类:

var Point = Object.extend({
    includes: [
        Mixin1,
        Mixin2
    ],
    self: {
        // class or "static" methods and properties go here
    },
    prototype: {
        // instance methods and properties go here
    }
});

var Point3D = Point.extend({ ... });

它为" mixins"提供支持。如果它们被声明为这样:

var Mixin = {
    includes: [
        // Yup, mixins can include mixins too
    ],
    included: function(Klass) {
        // Klass is the constructor function that just included this mixin
    },
    self: {
        // class or "static" methods and properties go here
    },
    prototype: {
        // instance methods and properties go here
    }
};

有些人会反对打字本地课程,但我全都是为了它。

为什么我走这条路:

  • instanceof操作员仍然可以使用
  • 我想继承实例和类级别方法
  • 我想要一些适用于大多数现有JavaScript框架的东西
  • 支持Mixins,根据具体情况,可以是一个方便的功能或拐杖。