我重写一个JavaScript项目,我希望能够使用面向对象的方法来组织,目前的代码是一团糟。 主要关注的是,这个JavaScript应该为第三方网站内构件运行,我不能把它与其他网站可以使用其他JavaScript库冲突。
所以我在寻找一种方式来写“类像”继承在具有下列要求的JavaScript:
- 不需要外部库或事物,将与外部库冲突(即排除了从外部库复制和粘贴)。
- 简约 - 我不想支持代码要大那么几行代码,我不希望开发者需要很多锅炉板的每次定义一个新的类或方法的时间。
- 应允许动态扩展的父对象,这样子对象看到的变化(原型)。
- 应允许构造函数链。
- 应该允许
super
类型的呼叫。 - 如果还是觉得JavaScript的杂交。
起初,我试图用简单的原型链的工作:
function Shape(x,y) {
this.x = x;
this.y = y;
this.draw = function() {
throw new Error("Arbitrary shapes cannot be drawn");
}
}
function Square(x,y,side) {
this.x = x;
this.y = y;
this.side = side;
this.draw = function() {
gotoXY(this.x,this.y); lineTo(this.x+this.side, this.y); ...
}
}
Square.prototype = new Shape();
这解决了要求1,2和6,但ID不允许超级电话(新的功能覆盖父函数),构造函数链和动态延伸的家长不提供新的方法,以一个子类。
任何建议将受到欢迎。
Answer 1:
我建议以下模式,这使得使用的clone
功能从protoypes而不是实例继承:
function Shape(x, y) {
this.x = x;
this.y = y;
}
Shape.prototype.draw = function() {
throw new Error('Arbitrary shapes cannot be drawn');
};
function Square(x,y,side) {
Shape.call(this, x, y); // call super constructor
this.side = side;
}
// inherit from `Shape.prototype` and *not* an actual instance:
Square.prototype = clone(Shape.prototype);
// override `draw()` method
Square.prototype.draw = function() {
gotoXY(this.x,this.y); lineTo(this.x+this.side, this.y); // ...
};
这是很重要的方法,驻留在原型(这是理所应当的,无论如何,性能方面的原因),所以你可以通过调用一个超类的方法
SuperClass.prototype.aMethod.call(this, arg1, arg2);
对于一些语法糖 ,可以让JS看起来像一个传统的基于类的语言:
var Shape = Class.extend({
constructor : function(x, y) {
this.x = x;
this.y = y;
},
draw : function() {
throw new Error('Arbitrary shapes cannot be drawn');
}
});
var Square = Shape.extend({
constructor : function(x, y, side) {
Shape.call(this, x, y);
this.side = side
},
draw : function() {
gotoXY(this.x,this.y); lineTo(this.x+this.side, this.y); // ...
}
});
Answer 2:
道格拉斯Crockford的有两个好文章古典和原型在Javascript中继承,这应该是不错的开始。
Answer 3:
OK,在JavaScript中复制一个类/实例式系统的伎俩是,你只能在实例使用原型继承。 所以,你需要能够做出仅用于继承“非实例”的实例,并有一个初始化器方法从构造函数本身是分开的。
这是最小的系统我使用,传递一个特殊一次性值到构造为具有其构造对象而不初始化它(添加褶边前):
Function.prototype.subclass= function() {
var c= new Function(
'if (!(this instanceof arguments.callee)) throw(\'Constructor called without "new"\'); '+
'if (arguments[0]!==Function.prototype.subclass._FLAG && this._init) this._init.apply(this, arguments); '
);
if (this!==Object)
c.prototype= new this(Function.prototype.subclass._FLAG);
return c;
};
Function.prototype.subclass._FLAG= {};
使用的new Function()
是为了避免在形成子类的不必要的关闭()的方法。 你可以用一个漂亮取代它function() {...}
如果你喜欢表达。
用法是比较干净的,一般像Python风格仅略有笨拙的语法对象:
var Shape= Object.subclass();
Shape.prototype._init= function(x, y) {
this.x= x;
this.y= y;
};
Shape.prototype.draw= function() {
throw new Error("Arbitrary shapes cannot be drawn");
};
var Square= Shape.subclass();
Square.prototype._init= function(x, y, side) {
Shape.prototype._init.call(this, x, y);
this.side= side;
};
Square.prototype.draw= function() {
gotoXY(this.x, this.y);
lineTo(this.x+this.side, this.y); // ...
};
猴修补一个内置(功能)是有点怀疑,但使得它愉快的阅读,没有一个人可能要for...in
经过功能。
Answer 4:
最常见的模式,我发现研究这个问题是在描述时, Mozilla开发者网络 。 我已经更新了他们的榜样,包括一个超类方法,并显示在日志中的警报消息的电话:
// Shape - superclass function Shape() { this.x = 0; this.y = 0; } // superclass method Shape.prototype.move = function(x, y) { this.x += x; this.y += y; log += 'Shape moved.\n'; }; // Rectangle - subclass function Rectangle() { Shape.call(this); // call super constructor. } // subclass extends superclass Rectangle.prototype = Object.create(Shape.prototype); Rectangle.prototype.constructor = Rectangle; // Override method Rectangle.prototype.move = function(x, y) { Shape.prototype.move.call(this, x, y); // call superclass method log += 'Rectangle moved.\n'; } var log = ""; var rect = new Rectangle(); log += ('Is rect an instance of Rectangle? ' + (rect instanceof Rectangle) + '\n'); // true log += ('Is rect an instance of Shape? ' + (rect instanceof Shape) + '\n'); // true rect.move(1, 1); // Outputs, 'Shape moved.' alert(log);
- 在五年既然你问了这个问题,它似乎是继承浏览器的支持有所好转,所以我不认为你需要一个外部库。
- 这最起码的技术,我已经看到了,我不知道如果你考虑太多的样板。
- 它采用了原型,按照要求,所以添加新的方法到父到子对象也应该为他们提供。
- 你可以看到的例子构造函数链。
- 超级呼叫类型也是例子。
- 我不知道,如果它感觉的JavaScript十岁上下,你必须为你自己决定。
Answer 5:
你可以在他的著作“JavaScript中的好的部分”使用由克罗克福德提出的功能模式。 想法是使用closore使私有字段,并使用previleged功能来访问这些字段。 这里是一个满足您的要求,6解决方案之一:
var people = function (info) {
var that = {};
// private
var name = info.name;
var age = info.age;
// getter and setter
that.getName = function () {
return name;
};
that.setName = function (aName) {
name = aName;
};
that.getAge = function () {
return age;
};
that.setAge = function (anAge) {
age = anAge;
};
return that;
};
var student = function (info) {
// super
var that = people(info);
// private
var major = info.major;
that.getMajor = function () {
return major;
};
that.setMajor = function (aMajor) {
major = aMajor;
};
return that;
};
var itStudent = function (info) {
// super
var that = student(info);
var language = info.language;
that.getLanguage = function () {
return language;
};
that.setLanguage = function (aLanguage) {
language = aLanguage;
};
return that;
};
var p = person({name : "Alex", age : 24});
console.debug(p.age); // undefined
console.debug(p.getAge()); // 24
var s = student({name : "Alex", age : 24, major : "IT"});
console.debug(s.getName()); // Alex
console.debug(s.getMajor()); // IT
var i = itStudent({name : "Alex", age : 24, major : "IT", language : "js"});
console.debug(i.language); // Undefined
console.debug(i.getName()); // Alex
console.debug(i.getMajor()); // IT
console.debug(i.getLanguage()); // js
Answer 6:
也克罗克福德的灵感,但我有很好的经验,与他所谓的“功能性继承”使用“构造函数”。 因人而异。
UPDATE:对不起,我忘了:你还需要增加对象具有superior
方法来获得不错的访问超级方法。 不适合你,也许。
var makeShape = function (x, y) {
that = {};
that.x = x;
that.y = y;
that.draw = function() {
throw new Error("Arbitrary shapes cannot be drawn");
}
return that;
};
var makeSquare = function (x, y, side) {
that = makeShape(x, y);
that.side = side;
that.draw = function() {
gotoXY(that.x,that.y); lineTo(that.x+that.side, that.y); ...
}
return that;
};
文章来源: What will be a good minimalistic Javascript inheritance method?