Der*_*ang 4 javascript prototype function
通常人们会编写如下代码:
function Shape() {
this.x = 0;
this.y = 0;
}
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
}
Run Code Online (Sandbox Code Playgroud)
但是,我试图想出一种方法来定义原型上的函数,而不将函数定义与构造函数分开.这是我得到的:
Object.prototype.method = function(name, func) {
if (typeof(this.constructor.prototype[name]) === 'undefined') {
this.constructor.prototype[name] = func
}
}
Run Code Online (Sandbox Code Playgroud)
这允许您执行以下操作:
function Shape() {
this.x = 0;
this.y = 0;
this.method('move', function(x, y) {
this.x += x;
this.y += y;
})
}
Run Code Online (Sandbox Code Playgroud)
而且无论您创建多少次形状,该功能都只会被定义一次.
我知道扩充Object.prototype不被认为是一种好习惯.但除此之外,这种方法有任何缺点吗?
编辑:
约翰提出了一个好点; 我应该做的method不是可枚举的.这是修订版:
Object.defineProperty(Object.prototype, 'method', {
value: function(name, func) {
if (typeof(this.constructor.prototype[name]) === 'undefined') {
this.constructor.prototype[name] = func
}
},
enumerable: false
})
Run Code Online (Sandbox Code Playgroud)
让我们实际比较两种方式,看看哪一种更快:http://jsperf.com/traditional-oop-vs-derek-s-oop-variant
如您所见,您的方法比传统方法慢得多.原因是:
method每次创建一个新实例时都会创建一个新的匿名函数.它只会在一次之后才有用,它会浪费处理能力.prototype构造函数是否具有给定方法,并将该方法添加到prototypeif中.这似乎没必要.您不需要创建一个函数来为您执行此操作.恕我直言,函数调用只是额外的开销.既然你要求批评:
我知道扩充
Object.prototype不被认为是一种好习惯.但除此之外,这种方法有任何缺点吗?
除了速度非常慢之外,您的方法也会受到以下影响:
this.method是做什么的.他们需要阅读Object.prototype.method完全理解您的代码的定义.prototype在构造函数中定义属性是没有意义的.它只需要一次,之后它就会成为额外的行李.最好将构造函数逻辑和prototype属性分开.prototype将永远不会设置属性.当您尝试访问该属性时,这可能会导致问题prototype.例如,在prototype调用基本构造函数之前,将继承从no属性继承属性.我相信您的目标是将构造函数和prototype属性封装到单个实体中:
但是,我试图想出一种方法来定义原型上的函数,而不将函数定义与构造函数分开.
是否有捷径可寻?让我们看看,JavaScript是一种原型面向对象的语言.因此,我们应该更多地关注prototype而不是构造函数.

上图取自以下答案:https://stackoverflow.com/a/8096017/783743
该图显示了我们:
prototype,该属性指向构造函数的原型对象.constructor,该属性指向原型对象的构造函数.prototype构造函数,而不是构造函数.这是非常有用的信息.传统上我们总是首先创建一个构造函数,然后我们设置它的prototype属性.但是,这些信息告诉我们,我们可以先创建一个原型对象,然后constructor在其上定义属性.
例如,传统上我们可以写:
function Shape() {
this.x = 0;
this.y = 0;
}
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
};
Run Code Online (Sandbox Code Playgroud)
然而,使用我们新发现的知识,我们可能会写同样的东西:
var shape = {
constructor: function () {
this.x = 0;
this.y = 0;
},
move: function (x, y) {
this.x += x;
this.y += y;
}
};
Run Code Online (Sandbox Code Playgroud)
这两个例子中包含的信息是相同的.但是,我们需要一些额外的脚手架来使第二个例子起作用.特别是我们需要这样做:
var Shape = shape.constructor;
Shape.prototype = shape;
Run Code Online (Sandbox Code Playgroud)
这不是一个大问题.我们只是创建一个函数来为我们这样做:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以定义Shape如下:
var Shape = defclass({
constructor: function () {
this.x = 0;
this.y = 0;
},
move: function (x, y) {
this.x += x;
this.y += y;
}
});
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,在JavaScript中很容易实现封装.你需要做的就是侧身思考.然而,继承是一个不同的问题.你需要做更多的工作才能实现继承.
希望这有帮助.