27

我正在写一个图书馆。现在,我将所有内容都写在一个 .js 文件中,如下所示:

function doThis() {}
var thisVar = 5;

我不确定这是否正确,所以我考虑了:

function Lib() {
  this.doThis = function() {}
  this.thisVar = 5;
}

var lib = new Lib();

然后,在主程序文件上,我必须用“lib.”来调用所有内容,例如“lib.thisVar”或“lib.doThis();”。

有什么想法会更好,或者它们都可以接受吗?先感谢您。

4

8 回答 8

26

为了避免混淆全局命名空间,我使用了这样的结构:

var MyLib = {
    vars: {
        var1: 'value1',
        var2: 'value2'
    },
    func1: function () {
        return this.vars.var1;
    },
    func2: function () {
        alert("This is func2");
    }
};

MyLib.func1();
MyLib.func2();

您会注意到我将所有变量都放入了它们自己的子对象中,这样做纯粹是为了便于阅读和开发。


编辑1:

这是我使用的另一种方法

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() );

该结构利用JS 闭包和构造函数,因此很容易将私有变量保持私有。

编辑2:

此外,我还使用了不返回构造函数的不同闭包设置(例如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 : {}));

并在行动中看到它:

myLib('something').set('made public, outside of the closure by the `get` method');

myLib('something').get(function(a){
  console.log(a);
});

还请看一下我公开的方式myLib,考虑到它在哪里运行,以及它是如何被包含在内的。

编辑 3 (7/2017):

作为一个全栈(w/Node.js)JavaScript 工程师,随着 Browserify 的出现,我完全推荐使用 Nodejs 风格的module模式,利用 Gulp 或 Grunt 作为构建系统来编译多文件(解耦,更小代码位)到一个库中。

该模型有助于鼓励采用更实用的方法,允许开发人员将库中更常见的功能抽象到单独的文件中,从而使开发变得更加容易。

哦,使用 ES6!

// file: src/divideIntByFour.js

const divideIntByFour = (int) => {
    return int / 4;
};

module.exports = divideIntByFour;

...作为一个简单的例子

于 2012-11-28T13:35:07.213 回答
11

查看 JavaScript 模块模式。

http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth

你可以考虑让你的库与 require.js 兼容,这是一个可以做这种事情的框架。

http://requirejs.org

于 2012-11-28T13:33:21.500 回答
9

理论上两者都是可以接受的。但是两者都存在与应用程序中使用的其他部分/库发生命名冲突的风险。

在第一种情况下,您冒着为单个函数命名冲突的风险,而在后一种情况下,您冒着为库包装器 ( Lib) 选择的函数命名冲突的风险。

首选方法是将它们包装在单独的命名空间中,如本页所示:

http://frugalcoder.us/post/2010/02/11/js-classes.aspx

于 2012-11-28T13:31:12.603 回答
3

是的,后一种方法更好,因为它不会创建许多全局变量(“全局范围污染”),而是将它们命名在一个对象上。

但是,不需要构造函数 ( Lib),您lib只需实例化一次(遵循单例模式);你不需要原型。相反,使用简单的对象字面量:

var lib = {
    doThis: function() {
    },
    thisVar: 5
};

对于私有(虽然是静态的)变量和更好的代码组织,还可以查看模块模式(或此处):

var lib = (function(){
    var thisVar = 5;
    function doThis() {}
    return { // "export"
        doThat: doThis
    };
})();
于 2012-11-28T13:32:19.633 回答
2

帖子很旧,但也许我的 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;
}
于 2016-07-22T09:57:05.510 回答
1

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

这是一个立即使用 2 个参数调用的 IIFE:this和一个函数表达式,它们分别是参数globalfactory。这使您的实现范围保持私有并防止命名冲突。

如果脚本在浏览器中运行,this将是window,所以 window.MyLibrary 将等于factory()第二个参数中函数表达式返回的结果。这是库的 API。

于 2017-06-02T15:22:31.803 回答
0

后者更可取。特别是在编写库时,尽可能避免污染全局命名空间很重要。您的代码需要尽可能少地干扰现有代码。

于 2012-11-28T13:31:02.260 回答
-1

第二种方法是推荐的做法,但可以通过创建新的命名空间来改进。优点是您将能够避免可能发生的所有名称冲突,而且您将对代码有更好的控制。我创建了一个名为“MyNamespace”的命名空间,并将我的 Library 类存储在其中。这样即使有任何其他类名为“库”的文件,也不会发生名称冲突。

(function($){
    $.Library = function(){
        this.memory = {}; 
        this.doSomething  = function() {};
    };

$.Library.prototype = { //these will be common for all the objects 
    commonFunction : function() {

    },
    function2 : function() {

    }
};

})(MyNameSpace);

使用下面的代码,您可以为 Library 类实例化新对象。

<script>
var lib = new MyNamespace.Library;
</script>
于 2015-02-24T16:04:51.457 回答