当前位置: 首页 > 面试题库 >

Javascript中的Javascript模块

岑俊弼
2023-03-14
问题内容

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

这是代码:

 // 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 export表示法来实现模式。


问题答案:

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

因此,我将首先以不同的方式来研究如何使用Node.js模块模式,最后,我将说明如何组合“模块模式”和“ Node.js模块模式”。

在模块上,导入和导出

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

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

现在,第二个模块baz.js可以“导入”该模块foo.js并访问该属性bar。在Node中,我们通过使用名为的全局函数来实现此效果require。如下所示:

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

技术1 –扩展具有其他功能的导出对象

因此,一种在模块中公开功能的技术包括向module.exports对象添加功能和属性。在这种情况下,Node提供了对导出对象的直接访问,使我们的事情变得更简单。例如:

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

如您所料,导入此模块时,该模块的用户将获得对该exports对象的引用,从而可以访问其中公开的所有功能。

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

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

至此,您可能会怀疑,鉴于事实module.exports仅仅是一个对象,它公开了模块的公共部分,因此我们可能会定义自己的对象,然后用我们自己的对象替换默认module.exports对象。例如:

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

module.exports = service;

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

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

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

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

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

module.exports = Foo;

该模块的用户可以简单地执行以下操作:

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

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

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

//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);
   }
};

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

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

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

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

因此,总的来说,它很简单,如下所示:公开的所有内容都是module.exports调用时得到的require。使用不同的技术,我们可以公开对象,构造函数,属性等。

基于所有这些示例,我说在我的代码中使用模块模式对我来说没有任何意义。

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

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

例如,执行以下操作:

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中TestModulemodule.exports对象相对应;在浏览器中运行时,则TestModule表示名称空间。

因此,如果您在Node中运行,则可以执行以下操作:

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

而且,如果您正在浏览器中运行,那么在加载此脚本之后,您可以直接访问名称空间TestModule。

TestModule.incrementCounter();


 类似资料:
  • JavaScript 模块 前端 ClojureScript 依赖命名空间, 所以不能直接使用 npm 模块, 甚至 UMD 模块. 使用前需要做打包处理, 或者通过暴露在 window 对象的属性来调用. 已经打包的模块可以参考: http://cljsjs.github.io/ 后端 使用 Lumo 运行 ClojureScript 脚本时可以通过 js/require 调用 npm 模块.

  • 偷懒是程序员的优良品质,模式则是先人们总结的偷懒招式。Stoyan Stefanov 的这本书,从 JavaScript 的实际使用场景出发,提炼了不少可以让前端们偷懒的实用招式。模式的探索、创新,将永远是程序员自我提升的一条修炼之道。值得一读。

  • 本节将通过实例介绍JavaScript中的并发模型。 6.1.1 JavaScript并发模型简介 使用C语言开发过本地多线程程序的开发者想必对进程、线程的关系并不陌生,其中最重要的莫过于: 进程内的所有线程共享相同的内存地址空间。 因此上大部分多线程的C程序都工作于共享内存的模式下,线程之间可以无障碍的通过内存交换数据,但与此同时,对竞争性资源的管理事实上成为了多线程编程中最常遇到的问题——相信

  • JavaScript未来的模块化会是什么样子?这很难讲。如前所说,ES6已经开始起草这一块的标准,而AMD,CommonJS已经流行起来。通常,标准的制定,都是在有了实现的前提之下。不管怎样,我们先来展望一二吧。

  • 本文向大家介绍JavaScript中的函数模式详解,包括了JavaScript中的函数模式详解的使用技巧和注意事项,需要的朋友参考一下 JavaScript设计模式的作用是提高代码的重用性,可读性,使代码更容易的维护和扩展 在javascript中,函数是一类对象,这表示他可以作为参数传递给其他函数;此外,函数还可以提供作用域。 创建函数的语法 命名函数表达式 函数表达式 为变量 add 赋的值是

  • 本文向大家介绍理解javascript中的严格模式,包括了理解javascript中的严格模式的使用技巧和注意事项,需要的朋友参考一下 一、什么是严格模式 我们平时写的JavaScript代码一般都运行在正常模式中的,除了正常运行模式,ECMAscript 5添加了第二种运行模式:”严格模式”(strict mode)。看名字就知道,这种模式会让JavaScript在更严格的环境中运行。 包括IE