我一直在尝试学习如何向现有代码添加测试——目前正在阅读有效地使用遗留代码。我一直在尝试在 JavaScript 中应用一些原则,现在我正在尝试提取一个接口。
在寻找用 JavaScript 创建接口的过程中,我找不到很多东西——而我发现的关于继承的东西似乎有几种不同的方式。(有些人创建自己的基类以提供有用的方法,使继承更容易,有些人使用函数,有些人使用原型)。
什么是正确的方法?有一个在 JavaScript 中提取接口的简单示例吗?
我一直在尝试学习如何向现有代码添加测试——目前正在阅读有效地使用遗留代码。我一直在尝试在 JavaScript 中应用一些原则,现在我正在尝试提取一个接口。
在寻找用 JavaScript 创建接口的过程中,我找不到很多东西——而我发现的关于继承的东西似乎有几种不同的方式。(有些人创建自己的基类以提供有用的方法,使继承更容易,有些人使用函数,有些人使用原型)。
什么是正确的方法?有一个在 JavaScript 中提取接口的简单示例吗?
没有明确的正确方法,因为很多人在做很多不同的事情。有很多有用的模式。
Crockford建议您“随波逐流”,或者以符合 javascript 原型性质的方式编写 javascript。
当然,他继续表明 Netscape 建议的原始模型实际上已被破坏。他将其标记为“伪经典”,并指出了遵循该模型所涉及的许多误导和不必要的复杂性。
他编写了“对象”函数作为补救措施(现在称为 Object.create() )。它允许一些非常强大的原型模式。
当您必须使用遗留 javascript 时,开发一个干净的界面并不总是那么容易,尤其是当您处理大型系统时,通常包括多个库,并且每个库都实现了独特的样式和不同的继承模式。一般来说,我会说进行继承的“正确方法”是允许您编写一个干净的接口,该接口在您的遗留代码的上下文中表现良好,但也允许您随着时间的推移重构和消除旧的依赖关系.
考虑到主要库模式之间的差异,我发现在我自己的工作中最成功的途径是让我的接口完全独立于库接口。如果有帮助,我将使用库或模块,但不会被绑定。这使我能够重构大量代码,逐步淘汰一些库,并将库用作以后可以优化的脚手架。
沿着这些思路,我编写了受 Crockford 寄生继承模式启发的接口。这真的是简单的胜利。
在硬币的另一面,我敢肯定你会争论选择一个库,在你的团队中强制执行它,并符合它的继承模式和接口约定。
javascript中没有类,只有对象。
但是如果你坚持模拟基于类的面向对象模型,你可以使用这个:
函数子类(){ ParentClass.call(this); // 在此之后编写构造函数的其余部分。 }; ChildClass.prototype = jQuery.extend({}, ParentClass.prototype, ChildClass.prototype);
jQuery.extend 是 jQuery 库中的一个“浅拷贝”函数。您可以将其替换为任何其他对象复制/克隆功能。
你在看两种不同的东西。
首先你有接口。实现这一点最被接受的方式是通过 Duck Typing(“如果它看起来像一只鸭子并且像鸭子一样嘎嘎叫,那么它就是一只鸭子”)。这意味着如果一个对象实现了接口的一组方法,那么它就是那个接口。您可以通过一组定义接口的方法名称来实现这一点。然后检查一个对象是否实现了那个干扰,你看看它是否实现了那些方法。这是我整理的一个代码示例:
function Implements(obj, inter)
{
var len = inter.length, i = 0;
for (; i < len; ++i)
{
if (!obj[inter[i]])
return false;
}
return true;
}
var IUser = ["LoadUser", "SaveUser"];
var user = {
LoadUser : function()
{
alert("Load");
},
SaveUser : function()
{
alert("Save");
}
};
var notUser = {
LoadUser : function()
{
alert("Load");
}
};
alert(Implements(user, IUser));
alert(Implements(notUser, IUser));
现在你有了继承权。JS 没有内置继承;所以你必须手动实现它。这只是将一个对象的属性“复制”到另一个对象的问题。这是另一个代码示例(不完美,但它说明了这一点):
function InheritObject(base, obj)
{
for (name in base)
{
if (!obj[name])
obj[name] = base[name];
}
}
var Base = {
BaseFunc : function() { alert("BaseFunc from base"); },
InheritFunc : function() { alert("InheritFunc from base"); }
}
var Inherit = {
InheritFunc : function() { alert("InheritFunc from inherit"); },
AnotherFunc : function() { alert("AnotherFunc from inherit"); }
}
InheritObject(Base, Inherit);
Inherit.InheritFunc();
Inherit.BaseFunc();
Inherit.AnotherFunc();
Base.BaseFunc();
Base.InheritFunc();
你可能想看看http://www.mootools.net。它有我最喜欢的类实现。你肯定也想看看“Pro Javascript Design Patterns”
http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X
这本书详细介绍了如何在 javascript 中模拟 OOP。
另请查看 Dean Edwards 的 Base.js。你可以看看这里,博客文章是不言自明的。
Prototype 提供了自己的继承方式,来自http://www.prototypejs.org/api/class/create:
var Animal = Class.create({
initialize: function(name, sound) {
this.name = name;
this.sound = sound;
},
speak: function() {
alert(this.name + " says: " + this.sound + "!");
}
});
// subclassing Animal
var Snake = Class.create(Animal, {
initialize: function($super, name) {
$super(name, 'hissssssssss');
}
});