sup*_*kas 3 javascript constructor design-patterns
我正在寻找一个理智的解决JavaScript只有一个构造函数的问题.所以假设我们有一个类Point,我们希望允许从坐标创建对象.
我会在所有这些例子中忽略类型检查.
function Point(x, y) {
this.x = x;
this.y = y;
}
Run Code Online (Sandbox Code Playgroud)
简单.如何从其他点创建积分?
function Point(x, y) {
if (!y /* && x instanceof Point */) {
y = x.y;
x = x.x;
}
this.x = x;
this.y = y;
}
Run Code Online (Sandbox Code Playgroud)
这很快变成了一场噩梦.所以我想要的是一个设计模式,它将这两个构造函数分离(或者将一个分成两个,而不是).Objective-C有一个很好的模式.ObjC人用某物创造物体.
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.withPoint = function(point) {
return new Point(point.x, point.y);
};
Run Code Online (Sandbox Code Playgroud)
到目前为止,我非常喜欢这个.但现在我们有两种不同的语法.
var a = new Point(4, 2);
var b = Point.withPoint(a);
Run Code Online (Sandbox Code Playgroud)
好吧,这很容易,不是吗?只需添加Point.withCoordinates.但那么构造函数呢?把它藏起来?我不知道.我想这就是你进来的地方.
这就是我决定采用的方式:
var Point = {
withCoordinates: function(x, y) {
if (typeof x == 'number' && typeof y == 'number') {
this.x = x;
this.y = y;
return this;
}
throw TypeError('expected two numbers');
},
withPoint: function(point) {
if (typeof point.x == 'number' && typeof point.y == 'number') {
this.withCoordinates(point.x, point.y);
return this;
}
throw TypeError('expected a point');
}
};
var a = Object.create(Point).withCoordinates(0, 0);
var b = Object.create(Point).withPoint(a);
Run Code Online (Sandbox Code Playgroud)
优点:
缺点:
Number.MAX_SAFE_INTEGER)注意类型检查Point.withPoint.它允许点击事件等鸭类点.
function onClick(event) {
var position = Object.create(Point).withPoint(event);
}
Run Code Online (Sandbox Code Playgroud)
还要注意在某种默认ctor中缺少零初始化.积分实际上是一个非常好的例子,为什么这并不总是一个好主意.
就像在ObjC上一样,你可以有单独的"alloc"和"init"条目,例如:
function Point() {}
Point.prototype.withCoordinates = function(x, y) {
this.x = x;
this.y = y;
return this;
}
Point.prototype.withOffsetFromPoint = function(p, delta) {
this.x = p.x + delta;
this.y = p.y + delta;
return this;
}
p = new Point().withOffsetFromPoint(
new Point().withCoordinates(5, 6),
10);
console.log(p) // 15, 16
Run Code Online (Sandbox Code Playgroud)
其中虚拟构造函数基本上是"alloc"的东西.
同样以更现代的方式,没有new:
Point = {
withCoordinates: function(x, y) {
this.x = x;
this.y = y;
return this;
},
withOffsetFromPoint: function(p, delta) {
this.x = p.x + delta;
this.y = p.y + delta;
return this;
}
}
p = Object.create(Point).withOffsetFromPoint(
Object.create(Point).withCoordinates(5, 6),
10);
console.log(p)
Run Code Online (Sandbox Code Playgroud)
另一个(也许是最惯用的)选项是使构造函数接受命名参数(通过"options"对象):
p = new Point({ x:1, y:2 })
p = new Point({ point: someOtherPoint })
Run Code Online (Sandbox Code Playgroud)