如何编写可重用的 Javascript?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2608913/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I write reusable Javascript?
提问by aw crud
I've started to wrap my functions inside of Objects, e.g.:
我已经开始将我的函数包装在对象中,例如:
var Search = {
carSearch: function(color) {
},
peopleSearch: function(name) {
},
...
}
This helps a lot with readability, but I continue to have issues with reusabilty. To be more specific, the difficulty is in two areas:
这对提高可读性有很大帮助,但我仍然遇到可重用性问题。具体来说,难点在两个方面:
Receiving parameters. A lot of times I will have a search screen with multiple input fields and a button that calls the javascript search function. I have to either put a bunch of code in the onclick of the button to retrieve and then martial the values from the input fields into the function call, or I have to hardcode the HTML input field names/IDs so that I can subsequently retrieve them with Javascript. The solution I've settled on for this is to pass the field names/IDs into the function, which it then uses to retrieve the values from the input fields. This is simple but really seems improper.
Returning values. The effect of most Javascript calls tends to be one in which some visual on the screen changes directly, or as a result of another action performed in the call. Reusability is toast when I put these screen-altering effects at the end of a function. For example, after a search is completed I need to display the results on the screen.
接收参数。很多时候我会有一个带有多个输入字段的搜索屏幕和一个调用 javascript 搜索功能的按钮。我必须在按钮的 onclick 中放入一堆代码来检索,然后将输入字段中的值传送到函数调用中,或者我必须对 HTML 输入字段名称/ID 进行硬编码,以便随后可以检索它们使用 Javascript。我为此确定的解决方案是将字段名称/ID 传递到函数中,然后它使用该函数从输入字段中检索值。这很简单,但确实看起来不合适。
返回值。大多数 Javascript 调用的效果往往是屏幕上的某些视觉效果直接改变,或者作为调用中执行的另一个操作的结果。当我将这些改变屏幕的效果放在函数的末尾时,可重用性就大功告成了。例如,搜索完成后,我需要在屏幕上显示结果。
How do others handle these issues? Putting my thinking cap on leads me to believe that I need to have an page-specific layer of Javascript between each use in my application and the generic methods I create which are to be used application-wide. Using the previous example, I would have a search button whose onclick calls a myPageSpecificSearchFunction, in which the search field IDs/names are hardcoded, which marshals the parameters and calls the generic search function. The generic function would return data/objects/variables only, and would not directly read from or make any changes to the DOM. The page-specific search function would then receive this data back and alter the DOM appropriately.
其他人如何处理这些问题?把我的思维上限让我相信我需要在我的应用程序中的每次使用和我创建的要在应用程序范围内使用的通用方法之间有一个特定于页面的 Javascript 层。使用前面的示例,我将有一个搜索按钮,其 onclick 调用 myPageSpecificSearchFunction,其中搜索字段 ID/名称是硬编码的,它编组参数并调用通用搜索函数。泛型函数只会返回数据/对象/变量,不会直接读取 DOM 或对 DOM 进行任何更改。特定于页面的搜索功能然后将接收此数据并适当地更改 DOM。
Am I on the right path or is there a better pattern to handle the reuse of Javascript objects/methods?
我是在正确的道路上还是有更好的模式来处理 Javascript 对象/方法的重用?
回答by T.J. Crowder
Basic Pattern
基本模式
In terms of your basic pattern, can I suggest modifying your structure to use the module pattern and named functions:
就您的基本模式而言,我是否建议修改您的结构以使用模块模式和命名函数:
var Search = (function(){
var pubs = {};
pubs.carSearch = carSearch;
function carSearch(color) {
}
pubs.peopleSearch = peopleSearch;
function peopleSearch(name) {
}
return pubs;
})();
Yes, that looks more complicated, but that's partially because there's no helper function involved. Note that now, every function has a name (your previous functions were anonymous; the properties they were bound to had names, but the functions didn't, which has implications in terms of the display of the call stack in debuggers and such). Using the module pattern also gives you the ability to have completely private functions that only the functions within your Searchobject can access. (Just declare the functions within the big anonymous function and don't add them to pubs.) More on my rationale for that (with advantages and disadvantages, and why you can't combine the function declaration and property assignment) here.
是的,这看起来更复杂,但这部分是因为没有涉及辅助函数。请注意,现在,每个函数都有一个名称(您以前的函数是匿名的;它们绑定的属性有名称,但函数没有,这对调试器中调用堆栈的显示等有影响)。使用模块模式还使您能够拥有完全私有的函数,只有您Search对象中的函数才能访问这些函数。(只需在大匿名函数中声明函数,不要将它们添加到pubs。)更多关于我的理由(优点和缺点,以及为什么不能将函数声明和属性分配结合起来)here。
Retrieving Parameters
检索参数
One of the functions I really, really like from Prototypeis the Form#serializefunction, which walks through the form elements and builds a plain object with a property for each field based on the field's name. (Prototype's current – 1.6.1 – implementation has an issue where it doesn't preserve the orderof the fields, but it's surprising how rarely that's a problem.) It sounds like you would be well-served by such a thing and they're not hard to build; then your business logic is dealing with objects with properties named according to what they're related to, and has no knowledge of the actual form itself.
Prototype 中我真正非常喜欢的Form#serialize功能之一是函数,它遍历表单元素并根据字段名称为每个字段构建一个具有属性的普通对象。(Prototype 的当前 - 1.6.1 - 实现存在一个问题,即它不保留字段的顺序,但令人惊讶的是,这种问题很少发生。)听起来你会被这样的东西很好地服务,他们'不难建造;那么您的业务逻辑正在处理具有根据其相关内容命名的属性的对象,并且不知道实际表单本身。
Returning Values / Mixing UI and Logic
返回值/混合 UI 和逻辑
I tend to think of applications as objects and the connections and interactions between them. So I tend to create:
我倾向于将应用程序视为对象以及它们之间的连接和交互。所以我倾向于创造:
- Objects representing the business model and such, irrespective of interface (although, of course, the business modelis almost certainly partially driven by the interface). Those objects are defined in one place, but used both client- and server-side (yes, I use JavaScript server-side), and designed with serialization (via JSON, in my case) in mind so I can send them back and forth easily.
- Objects server-side that know how to use those to update the underlying store (since I tend to work on projects with an underlying store), and
- Objects client-side that know how to use that information to render to the UI.
- 代表业务模型等的对象,与接口无关(当然,业务模型几乎肯定部分由接口驱动)。这些对象在一个地方定义,但同时使用客户端和服务器端(是的,我使用 JavaScript 服务器端),并且在设计时考虑了序列化(在我的情况下通过 JSON),因此我可以来回发送它们容易地。
- 知道如何使用这些对象来更新底层存储的服务器端对象(因为我倾向于使用底层存储处理项目),以及
- 知道如何使用该信息呈现给 UI 的对象客户端。
(I know, hardly original!) I try to keep the store and rendering objects generic so they mostly work by looking at the public properties of the business objects (which is pretty much all of the properties; I don't use the patterns like Crockford's that let you really hide data, I find them too expensive). Pragmatism means sometimes the store or rendering objects just have to know what they're dealing with, specifically, but I do try to keep things generic where I can.
(我知道,几乎不是原创的!)我尝试保持存储和呈现对象的通用性,因此它们主要通过查看业务对象的公共属性(这几乎是所有属性;我不使用像Crockford 让你真正隐藏数据,我觉得它们太贵了)。实用主义意味着有时存储或渲染对象只需要知道它们正在处理什么,具体来说,但我确实尽量保持通用。
回答by Lewis
Javascript is ridiculously flexible which means that your design is especially important as you can do things in many different ways. This is what probably makes Javascript feel less like lending itself to re-usability.
Javascript 非常灵活,这意味着您的设计尤其重要,因为您可以以多种不同的方式做事。这可能是什么让 Javascript 感觉不太像是借给自己的可重用性。
There are a few different notations for declaring your objects (functions/classes) and then namespacing them. It's important to understand these differences. As mentioned in a comment on here 'namespacing is a breeze' - and is a good place to start.
有几种不同的符号可以用来声明你的对象(函数/类),然后给它们命名空间。了解这些差异很重要。正如这里的评论中提到的“命名空间是轻而易举的” - 并且是一个很好的起点。
I wouldn't be able to go far enough in this reply and would only be paraphrasing, so I recommend buying these books:
我无法在此回复中走得足够远,只能进行释义,因此我建议购买以下书籍:
回答by Mark
I started out using the module pattern, but then started doing everything in jQuery plugins. The plugins allow to pass page specific options.
我开始使用模块模式,但后来开始在jQuery 插件中做所有事情。插件允许传递特定于页面的选项。
Using jQuery would also let you rethink the way you identify your search terms and find their values. You might consider adding a class to every input, and use that class to avoid specifically naming each input.
使用 jQuery 还可以让您重新思考识别搜索词并找到它们的值的方式。您可能会考虑为每个输入添加一个类,并使用该类来避免专门命名每个输入。

