javascript 写一个库,什么结构?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13606188/
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
Writing a library, what structure?
提问by David Gomes
I'm writting a library. Right now, I have everything written in a single .js file that goes like:
我正在写一个图书馆。现在,我将所有内容都写在一个 .js 文件中,如下所示:
function doThis() {}
var thisVar = 5;
I was not sure if that was right, so I considered:
我不确定这是否正确,所以我考虑了:
function Lib() {
this.doThis = function() {}
this.thisVar = 5;
}
var lib = new Lib();
Then, on the main program files, I would have to call everything with "lib.", such as "lib.thisVar" or "lib.doThis();".
然后,在主程序文件上,我必须用“lib.”调用所有内容,例如“lib.thisVar”或“lib.doThis();”。
Any ideas on which would be better, or are they both acceptable? Thank you in advance.
任何想法会更好,或者它们都可以接受?先感谢您。
采纳答案by techfoobar
Both are acceptable theoretically. But both run the risk of naming collisions with other parts/libraries used in your application.
理论上两者都是可以接受的。但是两者都存在与应用程序中使用的其他部分/库发生命名冲突的风险。
In the first case, you run the risk of naming collisions for the individual functions, whereas in the latter case, you run the risk of naming collisions for the function you choose for the library wrapper (Lib
).
在第一种情况下,您冒着为单个函数命名冲突的风险,而在后一种情况下,您冒着为库包装器 ( Lib
)选择的函数命名冲突的风险。
The preferred method would be to wrap them up in a separate namespace as shown in this page:
首选方法是将它们包装在一个单独的命名空间中,如本页所示:
回答by honyovk
To avoid cluttering the global namespace, I use a structure like this:
为了避免混乱全局命名空间,我使用了这样的结构:
var MyLib = {
vars: {
var1: 'value1',
var2: 'value2'
},
func1: function () {
return this.vars.var1;
},
func2: function () {
alert("This is func2");
}
};
MyLib.func1();
MyLib.func2();
You will notice I placed all the variables into their own sub-object, this is done purely for easy reading and development.
你会注意到我把所有的变量都放到了它们自己的子对象中,这样做纯粹是为了方便阅读和开发。
EDIT 1:
编辑 1:
Here is another methodI use
这是我使用的另一种方法
var MyLib = (function MyLib() {
var _privateVars = {
"someVar": "This value made public by `someMethod`",
"privateVar": "Can't see this value"
};
// Return the constructor
return function MyLibConstructor() {
var _this = this; // Cache the `this` keyword
_this.someMethod = function () {
// Access a private variable
return _privateVars.someVar;
};
_this.someOtherMethod = function () {
// Some other functionality
};
};
}());
var myLib = new MyLib(); // invoke
console.log( myLib.someMethod() );
This structure utilizes JS Closuresand a constructor function, so its easy to keep private variables private.
这种结构利用了JS 闭包和一个构造函数,因此很容易将私有变量保持私有。
EDIT 2:
编辑2:
In addition, I've also used a different closure setup that does not return a constructor (e.g. var x = new MyLib();
).
此外,我还使用了不返回构造函数的不同闭包设置(例如var x = new MyLib();
)。
(function(window) {
var _private = {},
methods = {},
topic, init;
methods.set = function(value) {
// Set the property & value
_private[topic] = value;
return this;
};
// A simple get method
methods.get = function(callback) {
var response = null;
// Return the value of topic (property) in a callback
if (!!callback && typeof callback === 'function') {
if (_private.hasOwnProperty(topic)) {
response = _private[topic];
}
callback.call(this, response);
}
return this;
};
// Init method setting the topic and returning the methods.
init = function(_topic) {
topic = _topic;
return methods;
};
// Exposure when being used in an AMD environment, e.g. RequireJS
if (typeof define === 'function' && define.amd) {
define(function() {
return init;
});
return;
}
// Exposure when being used with NodeJS
if ('undefined' !== typeof module && module.exports) {
module.exports = init;
return;
}
// Last-in-the-line exposure to the window, if it exists
window.myLib = init;
// This line either passes the `window` as an argument or
// an empty Object-literal if `window` is not defined.
}(('undefined' !== typeof window) ? window : {}));
And to see it in action:
并在行动中看到它:
myLib('something').set('made public, outside of the closure by the `get` method');
myLib('something').get(function(a){
console.log(a);
});
Please also take a look at the way I am exposing myLib
, taking into account where it's being run, and how it's being included.
还请看一下我公开的方式myLib
,考虑到它在哪里运行,以及它是如何被包含在内的。
EDIT 3 (7/2017):
编辑 3 (7/2017):
As a full stack (w/Node.js) JavaScript engineer, and the advent of Browserify, I fully recommend the use of the Nodejs-style module
pattern utilizing either Gulp or Grunt as a build system for compiling a multi-file (decoupled, smaller bits of code) into one library.
作为一个全栈(w/Node.js)JavaScript 工程师,以及 Browserify 的出现,我完全推荐使用 Nodejs 风格的module
模式,利用 Gulp 或 Grunt 作为编译多文件(解耦,更小的位代码)到一个库中。
This model helps encourage a more functional approach, allowing developers to abstract more common functions within a library into separate files, making development a lot easier.
该模型有助于鼓励更多功能的方法,允许开发人员将库中的更多常见功能抽象到单独的文件中,从而使开发变得更加容易。
Oh, and use ES6!
哦,使用 ES6!
// file: src/divideIntByFour.js
const divideIntByFour = (int) => {
return int / 4;
};
module.exports = divideIntByFour;
...As a siplified example
...作为一个简化的例子
回答by Jim Blackler
Look at the JavaScript Module pattern.
查看 JavaScript 模块模式。
http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
You could consider making your library compatible with require.js, which is a framework for doing exactly this kind of thing.
你可以考虑让你的库与 require.js 兼容,这是一个做这种事情的框架。
回答by Bergi
Yes, the latter approach is better as it does not create many global variables ("global scope pollution") but namespaces them on an object.
是的,后一种方法更好,因为它不会创建许多全局变量(“全局范围污染”),而是将它们命名为对象。
Yet, there is no need for a constructor (Lib
), you would instantiate your lib
only once (following the singleton pattern); and you don't need a prototype. Instead, use a simple object literal:
然而,不需要构造函数 ( Lib
),您lib
只需实例化一次(遵循单例模式);而且你不需要原型。相反,使用一个简单的对象字面量:
var lib = {
doThis: function() {
},
thisVar: 5
};
For private (though static) variables, and better code organisation, also have a look at the module pattern(or here):
对于私有(虽然是静态的)变量和更好的代码组织,还可以查看模块模式(或此处):
var lib = (function(){
var thisVar = 5;
function doThis() {}
return { // "export"
doThat: doThis
};
})();
回答by thatOneGuy
Post is old but maybe my 2 cents may help. I have seen and done this with multiple libraries :
帖子很旧,但也许我的 2 美分可能会有所帮助。我已经看到并使用多个库完成了此操作:
nameOfLibrary = function() { //name of library needs to be unique enough not to conflict with anyones code
nameOfLibrary = {};
//you can declare variables or functions only visible to this scope anywhere here
var randomVar = 'testVar';
function onlyVisibleHere() { /* doSomething */ }
//if you want functions visible to outside set them like so
nameOfLibrary.nameOfFunction = function() {
//code to run
}
//lastly return your library
return nameOfLibrary;
}
回答by frosty
UMD
is generally what's used.
UMD
一般是用什么。
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.MyLibrary = factory());
}(this, (function () { 'use strict';
// Private implementation here
let secret = "message";
// Whatever is returned is what `global.MyLibrary` will be
return {
getSecret: () => secret
};
})));
console.log(MyLibrary.getSecret()); // "message"
console.log(secret); // Uncaught ReferenceError: secret is not defined
It's an IIFE that's immediately invoked with 2 arguments: this
and a function expression, which are the parameters global
and factory
respectively. This keeps the scope of your implementation private and prevents naming collisions.
它是一个 IIFE,立即使用 2 个参数调用:this
和一个函数表达式,它们分别是参数global
和factory
。这使您的实现范围保持私有并防止命名冲突。
If the script is run in the browser, this
will be window
, so window.MyLibrary will be equal to factory()
which is whatever ends up being returned from the function expression in the second argument. This is the library's API.
如果脚本在浏览器中运行,this
will window
,所以 window.MyLibrary 将等于factory()
which 最终从第二个参数中的函数表达式返回。这是图书馆的 API。
回答by Matt Ball
The latter is preferable. Particularly when writing libraries, it is important to avoid polluting the global namespace as much as possible. Your code needs to interfere as little as possible with existing code.
后者是优选的。特别是在编写库时,尽可能避免污染全局命名空间很重要。您的代码需要尽可能少地干扰现有代码。
回答by Rahul Goyal
The second approach is recommended practice, but that can be improved by creating a new Namespace. The advantage is that you will be able to avoid all name collisions that can occur plus you will have a better control over your code. I have created a namespace called "MyNamespace" and I store my Library class inside that. This way even if there is any other file which has class name "Library", there will be no name collision.
第二种方法是推荐的做法,但可以通过创建新的命名空间来改进。优点是您将能够避免可能发生的所有名称冲突,并且您将更好地控制您的代码。我创建了一个名为“MyNamespace”的命名空间,并将我的 Library 类存储在其中。这样即使有任何其他类名为“Library”的文件,也不会发生名称冲突。
(function($){
$.Library = function(){
this.memory = {};
this.doSomething = function() {};
};
$.Library.prototype = { //these will be common for all the objects
commonFunction : function() {
},
function2 : function() {
}
};
})(MyNameSpace);
Using the below code you can instantiate new objects for Library class.
使用以下代码,您可以为 Library 类实例化新对象。
<script>
var lib = new MyNamespace.Library;
</script>