Javascript 中的 Javascript 模块 [英] Javascript Module in Javascript

查看:14
本文介绍了Javascript 中的 Javascript 模块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,问题很简单.我想使用两个 JavaScript 文件:一个遵循模块模式,另一个调用第一个.我使用 Node.js 测试了所有代码.当所有代码都在一个文件中时,它可以工作,但如果我将代码拆分为两个文件,则会出现错误.

Ok the problem is simple. I want use two JavaScript files: one following the module pattern and another one that calls the firs one. I tested all the code using Node.js. When all the code is in one file it works but if I split the code in two files I get an error.

代码如下:

 // module.js

var testModule = (function(){
"use strict";

var counter = 0;

return {
    incrementCounter : function(){
        return counter++;
    },
    resetCounter : function(){
        console.log("Last Counter Value before RESET :" + counter);
        counter = 0;
    };
};

 })();

 // script.js 

 var testModule = require('./module.js');  // i'm not sure about require or import
 "use strict";

testModule.incrementCounter();
testModule.resetCounter();

PS:我想使用 Javascript 符号而不是 Node 导出符号来实现模式.

PS: I want use the Javascript notation not the Node export notation to implement the pattern.

推荐答案

我首先要说的是不清楚为什么要在 Node.js 中使用模块模式".我的意思是,您建议的模块模式在客户端 JavaScript 中更有意义,即浏览器中的 JavaScript,但如果您的代码打算在 Node.js 中运行,那么您可以利用 Node.js 中已经存在的模块功能我个人认为在这种情况下强制使用模块模式没有价值.

I will start by saying that it is not clear why you want to use the "module pattern" with Node.js. I mean, the module pattern that you suggest make more sense in the client-side JavaScript, that is, JavaScript in the browser, but if your code is intended to run in Node.js then you can exploit the module functionality already present in Node and I personally do not see value in forcing the use of the module pattern in this case.

所以,我将首先以不同的方式深入研究使用 Node.js 模块模式,最后我会解释我将如何结合模块模式"和Node.js 模块模式".

So, I will delve first in different ways to use the Node.js module pattern, and at the end I explain how I would combine the "module pattern" and the "Node.js module pattern".

关于模块,导入和导出

让我们从最明显和最简单的事情开始.从使用 Node 的第一天起,每个人可能都会学到一些东西:每个代码文件都被视为一个模块.我们在其中声明的变量、属性、函数、构造函数对模块来说是私有的,其他模块无法访问或使用它们,除非模块的程序员明确地将它们公开给公众;即我们在模块中声明的所有内容默认情况下都被封装并隐藏起来,除非另有明确说明.为了公开某些东西,程序员可以访问一个叫做 module 的特殊对象,它有一个叫做 exports 的特殊属性.您在 module.exports 对象中发布的所有内容都对其他模块公开可用.例如,在下面的代码中,除了 foo.js 之外的任何其他模块都无法访问变量 pi,而名为 bar 的属性被创建对导入模块 foo.js 的任何其他模块公开可用.请注意,与在浏览器中执行的 JavaScript 相比,这是与 Node.js 中的 JavaScript 的根本区别,其中 JavaScript 文件中的函数可能会在全局对象(即 window)中公开暴露.>

Let’s start by the most obvious and simple thing. Something probably everyone learns since the first day of work with Node: every code file is considered a module. The variables, properties, functions, constructors that we declared in it are private to the module and other modules cannot gain access to them or use them unless the programmer of the module explicitly expose them to the public; namely everything we declare inside a module is encapsulated and hidden from the outside world by default unless explicitly stated otherwise. To expose something the programmer has access to a special object called module, which has a special property called exports. Everything that you publish in the module.exports object is made publicly available to other modules. For instance, in the code below, the variable pi is inaccessible to any other modules but foo.js, whereas the property named bar is made publicly available to any other modules importing the module foo.js. Note that this is a fundamental difference from JavaScript in Node.js when compared with JavaScript as executed in a browser where functions in a JavaScript file may be publicly exposed in a global object (i.e. window).

//module foo.js
var pi = 3.14;
module.exports.bar = 'Hello World';

现在第二个模块 baz.js 可以导入"模块 foo.js 并访问属性 bar.在 Node 中,我们通过使用一个名为 require 的全局函数来实现这个效果.大致如下:

Now a second module baz.js can "import" the module foo.js and gain access to the property bar. In Node, we achieve this effect by means of using a global function named require. Somewhat as follows:

//module baz.js
var foo = require('./foo');
console.log(foo.bar); //yields Hello World

技术 1 – 使用附加功能扩展导出对象

因此,在模块中公开功能的一种技术是向 module.exports 对象添加函数和属性.在这种情况下,Node 提供了对导出对象的直接访问,以简化我们的工作.例如:

So, one technique to expose the functionality in a module consists in adding functions and properties to the module.exports object. When this is the case, Node provides a direct access to the exports object to make things simpler for us. For instance:

//module foo.js
exports.serviceOne = function(){ };
exports.serviceTwo = function(){ };
exports.serviceThree = function(){ };

正如您所料,此模块的用户在导入它时,将获得对 exports 对象的引用,从而他们将获得对其中公开的所有功能的访问权.

And as you might expect, the users of this module, at importing it, would obtain a reference to the exports object and by this they would gain access to all the functionality exposed in it.

//module bar.js
var foo = require('./foo');
foo.serviceOne();
foo.serviceTwo();
foo.serviceThree();

技术 2 – 用另一个对象替换默认导出对象

此时你可能怀疑,鉴于 module.exports 只是一个暴露模块公共部分的对象,那么我们可能会定义我们自己的对象,然后替换默认的 module.exports 对象与我们自己的.例如:

By this point you probably suspect that given the fact that module.exports is just an object that exposes the public part of a module then we could probably define our own object and then replace the default module.exports object with our own. For instance:

//module foo.js
var service = {
   serviceOne: function(){ },
   serviceTwo: function(){ },
   serviceThree = function(){ }
};

module.exports = service;

最后一个示例中的代码与上一个示例中的代码完全一样,只是这次我们显式地创建了我们的导出对象,而不是使用 Node 默认提供的对象.

The code in this last example would behave exactly as the code in the previous example, it’s just that this time we have explicitly created our exported object instead of using the one provided by default by Node.

技巧 3 – 用构造函数替换默认导出对象

在到目前为止的示例中,我们一直使用对象的实例作为暴露的目标.然而,在某些情况下,允许用户根据需要创建给定类型的多个实例似乎更方便.没有什么能阻止我们用其他类型的对象(如构造函数)替换 module.exports 对象.在下面的示例中,我们公开了一个构造函数,用户可以使用它来创建 Foo 类型的许多实例.

In the examples so far we have always used an instance of an object as our exposed target. However there are occasions in which it may seem more convenient to allow the user to create as many instances of a given type as she wants. Nothing prevents us from replacing the module.exports object with other types of objects like a constructor function. In the example below we expose a constructor which the user can use to create many instances of the Foo type.

//module Foo.js
function Foo(name){
   this.name = name;
}

Foo.prototype.serviceOne = function(){ };
Foo.prototype.serviceTwo = function(){ };
Foo.prototype.serviceThree = function(){ };

module.exports = Foo;

这个模块的用户可以简单地做这样的事情:

And the user of this module can simply do something like this:

//module bar.js
var Foo = require('./Foo');
var foo = new Foo('Obi-wan');
foo.serviceOne();
foo.serviceTwo();
foo.serviceThree();

技术 4 – 用普通旧函数替换默认导出对象

现在很容易想象,如果我们可以使用构造函数,那么我们也可以使用任何其他普通的旧 JavaScript 函数作为在 module.exports 中公开的目标.如以下示例所示,我们导出的函数允许此模块的用户访问其他几个封装的服务对象之一.

It is easy to imagine now that if we can use a constructor function then we might just as well be able to use any other plain old JavaScript function as the target exposed in module.exports. As in the following example in which our exported function allows the user of this module to gain access to one of several other encapsulated service objects.

//foo.js
var serviceA = {};
serviceA.serviceOne = function(){ };
serviceA.serviceTwo = function(){ };
serviceA.serviceThree = function(){ };

var serviceB = {};
serviceB.serviceOne = function(){ };
serviceB.serviceTwo = function(){ };
serviceB.serviceThree = function(){ };

module.exports = function(name){
   switch(name){
      case 'A': return serviceA;
      case 'B': return serviceB;
      default: throw new Error('Unknown service name: ' + name);
   }
};

现在,导入此模块的用户收到对上面声明的匿名函数的引用,然后她可以简单地调用该函数来访问我们封装的对象之一.例如:

Now the user that imports this module receives a reference to our anonymous function declared above and then she can simply invoke the function to gain access to one of our encapsulated objects. For instance:

//module bar.js
var foo = require('./foo');
var obj = foo('A');
obj.serviceOne();
obj.serviceTwo();
obj.serviceThree();

许多程序员通常会调用 require 立即返回的函数,而不是先将其分配给引用.例如:

Many programmers ordinarily invoke the function immediately returned by require instead of assigning it to a reference first. For instance:

//module bar.js
var foo = require('./foo')('A');
foo.serviceOne();
foo.serviceTwo();
foo.serviceThree();

所以,总而言之,它很简单:我们在 module.exports 中公开的所有内容都是我们在调用 require 时得到的.并且使用不同的技术我们可以公开对象、构造函数、属性等.

So, in summary, it is as simple as follows: everything that we expose in module.exports is what we get when we invoke require. And using different techniques we could expose objects, constructors functions, properties, etc.

基于所有这些例子,我说在你的代码中使用模块模式是没有意义的.

Based on all these examples I say that it does not make sense for me to use a the module pattern in your code.

使用模块模式和 Node.js 模块

但是,如果您要创建一个在 Node.js 和浏览器中都使用的库,那么同时使用这两种模式是有意义的.不过,这在你的问题中并不明显.但如果是这样,那么您可以将这两个想法结合在一起.

However, if you would be creating a library that you would like to use in both Node.js and in the browser, then using both patterns could make sense. That is not evident in your question, though. But if that's the case, then you could combine the two ideas together.

例如,做这样的事情:

var TestModule;

(function (TestModule) {

    var counter = 0;
    TestModule.incrementCounter = function(){
        return counter++;
    };
    TestModule.resetCounter = function(){
        console.log('Last Counter Value before RESET :' + counter);
        counter = 0;
    };

    return TestModule;

})(typeof module === 'undefined' 
     ? (TestModule || (TestModule = {})) 
     : module.exports);

在 Node.js 中运行时,然后在 IIFE 中的 TestModule对应的是module.exports对象,在浏览器中运行时,TestModule代表一个命名空间.

When running in Node.js, then within the IIFE the TestModule corresponds to the module.exports object, when running in the browser, the TestModule represents a namespace.

所以,如果你在 Node 中运行,你可以这样做:

So, if you are running in Node, you can do:

var testModule = require('./testModule');
testModule.incrementCounter();

如果你是在浏览器中运行,那么加载这个脚本之后你就可以直接访问命名空间TestModule了.

And if you are running in the browser, then after loading this script you can access the namespace TestModule directly.

TestModule.incrementCounter();

这篇关于Javascript 中的 Javascript 模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆