javascript模块_JavaScript模块:新手指南

javascript模块

by Preethi Kasireddy

通过Preethi Kasireddy

JavaScript模块:新手指南 (JavaScript Modules: A Beginner’s Guide)

If you’re a newcomer to JavaScript, jargon like “module bundlers vs. module loaders,” “Webpack vs. Browserify” and “AMD vs. CommonJS” can quickly become overwhelming.

如果您是JavaScript的新手,诸如“模块捆绑器与模块加载器”,“ Webpack与浏览器”和“ AMD与CommonJS”之类的术语可能很快就会变得不知所措。

The JavaScript module system may be intimidating, but understanding it is vital for web developers.

JavaScript模块系统可能令人生畏,但了解它对Web开发人员至关重要。

In this post, I’ll unpack these buzzwords for you in plain English (and a few code samples). I hope you find it helpful!

在这篇文章中,我将用简单的英语(和一些代码示例)为您解压缩这些流行词。 我希望你觉得这对你有帮助!

Note: for simplicity’s sake, this will be divided into two sections: Part 1 will dive into explaining what modules are and why we use them. Part 2 (posted next week) will walk through what it means to bundle modules and the different ways to do so.

注意:为简单起见,这将分为两部分:第1部分将深入介绍什么是模块以及我们为何使用它们。 第2部分(下周发布)将逐步介绍捆绑模块的含义以及不同的捆绑方式。

第1部分:有人可以再解释一下什么模块吗? (Part 1: Can someone please explain what modules are again?)

Good authors divide their books into chapters and sections; good programmers divide their programs into modules.

好的作者将他们的书分为章节。 优秀的程序员将其程序分为模块。

Like a book chapter, modules are just clusters of words (or code, as the case may be).

就像一本书的章节一样,模块只是单词(或代码,视情况而定)的群集。

Good modules, however, are highly self-contained with distinct functionality, allowing them to be shuffled, removed, or added as necessary, without disrupting the system as a whole.

但是,好的模块是高度独立的,具有独特的功能,可以根据需要对它们进行改组,删除或添加,而不会破坏整个系统。

为什么要使用模块? (Why use modules?)

There are a lot of benefits to using modules in favor of a sprawling, interdependent codebase. The most important ones, in my opinion, are:

使用支持广泛的,相互依赖的代码库的模块有很多好处。 我认为最重要的是:

1) Maintainability: By definition, a module is self-contained. A well-designed module aims to lessen the dependencies on parts of the codebase as much as possible, so that it can grow and improve independently. Updating a single module is much easier when the module is decoupled from other pieces of code.

1)可维护性:根据定义,模块是独立的。 精心设计的模块旨在尽可能减少对代码库各部分的依赖,从而使其能够独立增长和改进。 当模块与其他代码解耦时,更新单个模块要容易得多。

Going back to our book example, if you wanted to update a chapter in your book, it would be a nightmare if a small change to one chapter required you to tweak every other chapter as well. Instead, you’d want to write each chapter in such a way that improvements could be made without affecting other chapters.

回到我们的书本示例,如果您想更新书中的一章,那么对一章进行小的更改也需要您对其他每一章进行调整,那将是一场噩梦。 相反,您希望以一种可以在不影响其他章节的情况下进行改进的方式编写每一章。

2) Namespacing: In JavaScript, variables outside the scope of a top-level function are global (meaning, everyone can access them). Because of this, it’s common to have “namespace pollution”, where completely unrelated code shares global variables.

2)命名空间:在JavaScript中,顶级函数范围之外的变量是全局变量(意味着每个人都可以访问它们)。 因此,通常会发生“命名空间污染”,其中完全不相关的代码共享全局变量。

Sharing global variables between unrelated code is a big no-no in development.

在不相关的代码之间共享全局变量在开发中是一个很大的禁忌

As we’ll see later in this post, modules allow us to avoid namespace pollution by creating a private space for our variables.

正如我们将在本文的后面看到的那样,模块允许我们通过为变量创建私有空间来避免名称空间污染。

3) Reusability: Let’s be honest here: we’ve all copied code we previously wrote into new projects at one point or another. For example, let’s imagine you copied some utility methods you wrote from a previous project to your current project.

3)可重用性:在这里说实话:我们已经将以前编写的代码复制到一个新的项目中。 例如,假设您将从先前项目编写的一些实用程序方法复制到当前项目。

That’s all well and good, but if you find a better way to write some part of that code you’d have to go back and remember to update it everywhere else you wrote it.

一切都很好,但是如果您找到一种更好的方法来编写该代码的某些部分,则必须回过头来,并记住要在其他所有编写代码的地方对其进行更新。

This is obviously a huge waste of time. Wouldn’t it be much easier if there was — wait for it — a module that we can reuse over and over again?

这显然是浪费时间。 如果有一个-可以等待-一个我们可以一遍又一遍地重用的模块,难道不是容易得多吗?

如何合并模块? (How can you incorporate modules?)

There are many ways to incorporate modules into your programs. Let’s walk through a few of them:

有很多方法可以将模块合并到程序中。 让我们看一下其中的一些:

模块模式 (Module pattern)

The Module pattern is used to mimic the concept of classes (since JavaScript doesn’t natively support classes) so that we can store both public and private methods and variables inside a single object — similar to how classes are used in other programming languages like Java or Python. That allows us to create a public facing API for the methods that we want to expose to the world, while still encapsulating private variables and methods in a closure scope.

Module模式用于模仿类的概念(因为JavaScript本身不支持类),因此我们可以将公共方法和私有方法以及变量存储在单个对象中-类似于在Java等其他编程语言中使用类的方式或Python。 这使我们可以为要公开的方法创建面向公众的API,同时仍将私有变量和方法封装在闭包范围内。

There are several ways to accomplish the module pattern. In this first example, I’ll use an anonymous closure. That’ll help us accomplish our goal by putting all our code in an anonymous function. (Remember: in JavaScript, functions are the only way to create new scope.)

有几种方法可以完成模块模式。 在第一个示例中,我将使用匿名闭包。 通过将所有代码放入匿名函数中,这将帮助我们实现目标。 (请记住:在JavaScript中,函数是创建新范围的唯一方法。)

Example 1: Anonymous closure

示例1:匿名闭包

(function () {
  // We keep these variables private inside this closure scope
  
  var myGrades = [93, 95, 88, 0, 55, 91];
  
  var average = function() {
    var total = myGrades.reduce(function(accumulator, item) {
      return accumulator + item}, 0);
    
      return 'Your average grade is ' + total / myGrades.length + '.';
  }

  var failing = function(){
    var failingGrades = myGrades.filter(function(item) {
      return item < 70;});
      
    return 'You failed ' + failingGrades.length + ' times.';
  }

  console.log(failing());

}());

// ‘You failed 2 times.’

With this construct, our anonymous function has its own evaluation environment or “closure”, and then we immediately evaluate it. This lets us hide variables from the parent (global) namespace.

通过这种构造,我们的匿名函数具有其自己的评估环境或“关闭”,然后我们立即对其进行评估。 这使我们可以从父(全局)名称空间中隐藏变量。

What’s nice about this approach is that is that you can use local variables inside this function without accidentally overwriting existing global variables, yet still access the global variables, like so:

这种方法的优点在于,您可以在此函数内使用局部变量,而不会意外覆盖现有的全局变量,但仍可以访问全局变量,如下所示:

var global = 'Hello, I am a global variable :)';

(function () {
  // We keep these variables private inside this closure scope
  
  var myGrades = [93, 95, 88, 0, 55, 91];
  
  var average = function() {
    var total = myGrades.reduce(function(accumulator, item) {
      return accumulator + item}, 0);
    
    return 'Your average grade is ' + total / myGrades.length + '.';
  }

  var failing = function(){
    var failingGrades = myGrades.filter(function(item) {
      return item < 70;});
      
    return 'You failed ' + failingGrades.length + ' times.';
  }

  console.log(failing());
  console.log(global);
}());

// 'You failed 2 times.'
// 'Hello, I am a global variable :)'

Note that the parenthesis around the anonymous function are required, because statements that begin with the keyword function are always considered to be function declarations (remember, you can’t have unnamed function declarations in JavaScript.) Consequently, the surrounding parentheses create a function expression instead. If you’re curious, you can read more here.

请注意,必须在匿名函数周围加上括号,因为以关键字function开头的语句始终被视为函数声明(请记住,JavaScript中不能包含未命名的函数声明。)因此,括号内会创建函数表达式代替。 如果您好奇,可以在这里阅读更多内容

Example 2: Global import Another popular approach used by libraries like jQuery is global import. It’s similar to the anonymous closure we just saw, except now we pass in globals as parameters:

示例2:全局导入 jQuery之类的库使用的另一种流行方法是全局导入。 它类似于我们刚刚看到的匿名闭包,只不过现在我们将全局变量作为参数传递:

(function (globalVariable) {

  // Keep this variables private inside this closure scope
  var privateFunction = function() {
    console.log('Shhhh, this is private!');
  }

  // Expose the below methods via the globalVariable interface while
  // hiding the implementation of the method within the 
  // function() block

  globalVariable.each = function(collection, iterator) {
    if (Array.isArray(collection)) {
      for (var i = 0; i < collection.length; i++) {
        iterator(collection[i], i, collection);
      }
    } else {
      for (var key in collection) {
        iterator(collection[key], key, collection);
      }
    }
  };

  globalVariable.filter = function(collection, test) {
    var filtered = [];
    globalVariable.each(collection, function(item) {
      if (test(item)) {
        filtered.push(item);
      }
    });
    return filtered;
  };

  globalVariable.map = function(collection, iterator) {
    var mapped = [];
    globalUtils.each(collection, function(value, key, collection) {
      mapped.push(iterator(value));
    });
    return mapped;
  };

  globalVariable.reduce = function(collection, iterator, accumulator) {
    var startingValueMissing = accumulator === undefined;

    globalVariable.each(collection, function(item) {
      if(startingValueMissing) {
        accumulator = item;
        startingValueMissing = false;
      } else {
        accumulator = iterator(accumulator, item);
      }
    });

    return accumulator;

  };

 }(globalVariable));

In this example, globalVariable is the only variable that’s global. The benefit of this approach over anonymous closures is that you declare the global variables upfront, making it crystal clear to people reading your code.

在此示例中, globalVariable是唯一的全局变量。 这种方法相对于匿名闭包的好处在于,您可以预先声明全局变量,从而使阅读代码的人一目了然。

Example 3: Object interfaceYet another approach is to create modules using a self-contained object interface, like so:

示例3:对象接口另一种方法是使用自包含对象接口创建模块,如下所示:

var myGradesCalculate = (function () {
    
  // Keep this variable private inside this closure scope
  var myGrades = [93, 95, 88, 0, 55, 91];

  // Expose these functions via an interface while hiding
  // the implementation of the module within the function() block

  return {
    average: function() {
      var total = myGrades.reduce(function(accumulator, item) {
        return accumulator + item;
        }, 0);
        
      return'Your average grade is ' + total / myGrades.length + '.';
    },

    failing: function() {
      var failingGrades = myGrades.filter(function(item) {
          return item < 70;
        });

      return 'You failed ' + failingGrades.length + ' times.';
    }
  }
})();

myGradesCalculate.failing(); // 'You failed 2 times.' 
myGradesCalculate.average(); // 'Your average grade is 70.33333333333333.'

As you can see, this approach lets us decide what variables/methods we want to keep private (e.g. myGrades) and what variables/methods we want to expose by putting them in the return statement (e.g. average & failing).

如您所见,这种方法使我们可以决定将哪些变量/方法设为私有(例如myGrades ),以及通过将它们放入return语句中来公开哪些变量/方法(例如averagefailing )。

Example 4: Revealing module patternThis is very similar to the above approach, except that it ensures all methods and variables are kept private until explicitly exposed:

示例4:显示模块模式这与上面的方法非常相似,不同之处在于它确保在明确公开之前,所有方法和变量都保持私有状态:

var myGradesCalculate = (function () {
    
  // Keep this variable private inside this closure scope
  var myGrades = [93, 95, 88, 0, 55, 91];
  
  var average = function() {
    var total = myGrades.reduce(function(accumulator, item) {
      return accumulator + item;
      }, 0);
      
    return'Your average grade is ' + total / myGrades.length + '.';
  };

  var failing = function() {
    var failingGrades = myGrades.filter(function(item) {
        return item < 70;
      });

    return 'You failed ' + failingGrades.length + ' times.';
  };

  // Explicitly reveal public pointers to the private functions 
  // that we want to reveal publicly

  return {
    average: average,
    failing: failing
  }
})();

myGradesCalculate.failing(); // 'You failed 2 times.' 
myGradesCalculate.average(); // 'Your average grade is 70.33333333333333.'

That may seem like a lot to take in, but it’s just the tip of the iceberg when it comes to module patterns. Here are a few of the resources I found useful in my own explorations:

这看起来可能需要很多,但这只是模块模式的冰山一角。 以下是我发现对自己的探索有用的一些资源:

CommonJS和AMD (CommonJS and AMD)

The approaches above all have one thing in common: the use of a single global variable to wrap its code in a function, thereby creating a private namespace for itself using a closure scope.

最重要的是,这些方法有一个共同点:使用单个全局变量将其代码包装在函数中,从而使用闭包作用域为其自身创建私有名称空间。

While each approach is effective in its own way, they have their downsides.

尽管每种方法都以其自己的方式有效,但它们也有缺点。

For one, as a developer, you need to know the right dependency order to load your files in. For instance, let’s say you’re using Backbone in your project, so you include the script tag for Backbone’s source code in your file.

首先,作为开发人员,您需要了解正确的依赖顺序来加载文件。例如,假设您在项目中使用Backbone,因此在文件中包含Backbone源代码的脚本标签。

However, since Backbone has a hard dependency on Underscore.js, the script tag for the Backbone file can’t be placed before the Underscore.js file.

但是,由于Backbone对Underscore.js有着严格的依赖性,因此Backbone文件的script标签不能放在Underscore.js文件之前。

As a developer, managing dependencies and getting these things right can sometimes be a headache.

作为开发人员,管理依赖关系并正确解决这些问题有时会令人头疼。

Another downside is that they can still lead to namespace collisions. For example, what if two of your modules have the same name? Or what if you have two versions of a module, and you need both?

另一个缺点是它们仍然可能导致名称空间冲突。 例如,如果您的两个模块具有相同的名称怎么办? 或者,如果您有一个模块的两个版本,而又需要两个版本,该怎么办?

So you’re probably wondering: can we design a way to ask for a module’s interface without going through the global scope?

因此,您可能想知道:我们能否设计一种无需遍历全局范围即可请求模块接口的方法?

Fortunately, the answer is yes.

幸运的是,答案是肯定的。

There are two popular and well-implemented approaches: CommonJS and AMD.

有两种流行且实现良好的方法:CommonJS和AMD。

普通JS (CommonJS)

CommonJS is a volunteer working group that designs and implements JavaScript APIs for declaring modules.

CommonJS是一个志愿者工作组,负责设计和实现用于声明模块JavaScript API。

A CommonJS module is essentially a reusable piece of JavaScript which exports specific objects, making them available for other modules to require in their programs. If you’ve programmed in Node.js, you’ll be very familiar with this format.

一个CommonJS的模块本质上是一种可重复使用的一段JavaScript代码其中出口特定对象,使它们可用于其他模块需要在他们的计划。 如果您使用Node.js编程,您将非常熟悉这种格式。

With CommonJS, each JavaScript file stores modules in its own unique module context (just like wrapping it in a closure). In this scope, we use the module.exports object to expose modules, and require to import them.

使用CommonJS,每个JavaScript文件都将模块存储在其自己的唯一模块上下文中(就像将其包装在闭包中一样)。 在此范围内,我们使用module.exports对象公开模块,并要求将其导入。

When you’re defining a CommonJS module, it might look something like this:

当您定义CommonJS模块时,它可能看起来像这样:

function myModule() {
  this.hello = function() {
    return 'hello!';
  }

  this.goodbye = function() {
    return 'goodbye!';
  }
}

module.exports = myModule;

We use the special object module and place a reference of our function into module.exports. This lets the CommonJS module system know what we want to expose so that other files can consume it.

我们使用特殊对象模块,并将我们函数的引用放入module.exports中 。 这使CommonJS模块系统知道我们要公开的内容,以便其他文件可以使用它。

Then when someone wants to use myModule, they can require it in their file, like so:

然后,当有人要使用myModule时 ,他们可以在文件中要求它,如下所示:

var myModule = require('myModule');

var myModuleInstance = new myModule();
myModuleInstance.hello(); // 'hello!'
myModuleInstance.goodbye(); // 'goodbye!'

There are two obvious benefits to this approach over the module patterns we discussed before:

与我们之前讨论的模块模式相比,此方法有两个明显的好处:

1. Avoiding global namespace pollution2. Making our dependencies explicit

1.避免全球命名空间污染2。 明确我们的依赖关系

Moreover, the syntax is very compact, which I personally love.

而且,语法非常紧凑,我个人很喜欢。

Another thing to note is that CommonJS takes a server-first approach and synchronously loads modules. This matters because if we have three other modules we need to require, it’ll load them one by one.

要注意的另一件事是,CommonJS采用服务器优先的方法并同步加载模块。 这很重要,因为如果我们有我们需要需要其他三个模块,它会加载它们一个接一个。

Now, that works great on the server but, unfortunately, makes it harder to use when writing JavaScript for the browser. Suffice it to say that reading a module from the web takes a lot longer than reading from disk. For as long as the script to load a module is running, it blocks the browser from running anything else until it finishes loading. It behaves this way because the JavaScript thread stops until the code has been loaded. (I’ll cover how we can work around this issue in Part 2 when we discuss module bundling. For now, that’s all we need to know).

现在,它在服务器上运行良好,但是不幸的是,这使得为浏览器编写JavaScript时更难使用。 我只想说,阅读从网络模块需要大量的时间比从磁盘读取。 只要加载模块的脚本一直在运行,它就会阻止浏览器运行其他任何东西,直到加载完成。 它的行为是这样的,因为JavaScript线程将停止直到代码被加载。 (在讨论模块捆绑时,我将在第2部分中介绍如何解决此问题。现在,这就是我们需要知道的全部内容)。

AMD公司 (AMD)

CommonJS is all well and good, but what if we want to load modules asynchronously? The answer is called Asynchronous Module Definition, or AMD for short.

CommonJS很好,但是如果我们要异步加载模块怎么办? 答案叫“异步模块定义”,简称AMD。

Loading modules using AMD looks something like this:

使用AMD加载模块如下所示:

define(['myModule', 'myOtherModule'], function(myModule, myOtherModule) {
  console.log(myModule.hello());
});

What’s happening here is that the define function takes as its first argument an array of each of the module’s dependencies. These dependencies are loaded in the background (in a non-blocking manner), and once loaded define calls the callback function it was given.

这里发生的是, define函数将每个模块依赖项的数组作为第一个参数。 这些依赖项在后台加载(以非阻塞方式),并且一旦加载了define便调用给定的回调函数。

Next, the callback function takes, as arguments, the dependencies that were loaded — in our case, myModule and myOtherModule — allowing the function to use these dependencies. Finally, the dependencies themselves must also be defined using the define keyword.

接下来,回调函数将加载的依赖项作为参数(在本例中为myModulemyOtherModule),以允许函数使用这些依赖项。 最后,还必须使用define关键字定义依赖项本身。

For example, myModule might look like this:

例如, myModule可能看起来像这样:

define([], function() {

  return {
    hello: function() {
      console.log('hello');
    },
    goodbye: function() {
      console.log('goodbye');
    }
  };
});

So again, unlike CommonJS, AMD takes a browser-first approach alongside asynchronous behavior to get the job done. (Note, there are a lot of people who strongly believe that dynamically loading files piecemeal as you start to run code isn’t favorable, which we’ll explore more when in the next section on module-building).

同样,与CommonJS不同的是,AMD采用浏览器优先的方法以及异步行为来完成工作。 (请注意,很多人坚信在您开始运行代码时动态地逐个加载文件是不利的,我们将在下一节关于模块构建的部分中进行更多探讨)。

Aside from asynchronicity, another benefit of AMD is that your modules can be objects, functions, constructors, strings, JSON and many other types, while CommonJS only supports objects as modules.

除了异步之外,AMD的另一个好处是您的模块可以是对象,函数,构造函数,字符串,JSON和许多其他类型,而CommonJS仅支持将对象作为模块。

That being said, AMD isn’t compatible with io, filesystem, and other server-oriented features available via CommonJS, and the function wrapping syntax is a bit more verbose compared to a simple require statement.

话虽这么说,AMD与CommonJS提供的io,文件系统和其他面向服务器的功能不兼容,并且与简单的require语句相比,函数包装的语法更加冗长。

UMD (UMD)

For projects that require you to support both AMD and CommonJS features, there’s yet another format: Universal Module Definition (UMD).

对于要求您同时支持AMD和CommonJS功能的项目,还有另一种格式:通用模块定义(UMD)。

UMD essentially creates a way to use either of the two, while also supporting the global variable definition. As a result, UMD modules are capable of working on both client and server.

UMD本质上创建了一种使用这两种方法之一的方式,同时还支持全局变量定义。 结果,UMD模块能够在客户端和服务器上工作。

Here’s a quick taste of how UMD goes about its business:

以下是UMD如何开展业务的快速体验:

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
      // AMD
    define(['myModule', 'myOtherModule'], factory);
  } else if (typeof exports === 'object') {
      // CommonJS
    module.exports = factory(require('myModule'), require('myOtherModule'));
  } else {
    // Browser globals (Note: root is window)
    root.returnExports = factory(root.myModule, root.myOtherModule);
  }
}(this, function (myModule, myOtherModule) {
  // Methods
  function notHelloOrGoodbye(){}; // A private method
  function hello(){}; // A public method because it's returned (see below)
  function goodbye(){}; // A public method because it's returned (see below)

  // Exposed public methods
  return {
      hello: hello,
      goodbye: goodbye
  }
}));

For more examples of UMD formats, check out this enlightening repo on GitHub.

有关UMD格式的更多示例,请在GitHub上查看此启发性仓库。

原生JS (Native JS)

Phew! Are you still around? I haven’t lost you in the woods here? Good! Because we have *one more* type of module to define before we’re done.

! 你还在吗 我没有在这里的树林迷路过你吗? 好! 因为在完成之前,我们需要再定义一个*类型的模块。

As you probably noticed, none of the modules above were native to JavaScript. Instead, we’ve created ways to emulate a modules system by using either the module pattern, CommonJS or AMD.

您可能已经注意到,以上所有模块都不是JavaScript固有的。 相反,我们已经创建了通过使用模块模式CommonJS或AMD来仿真模块系统的方法。

Fortunately, the smart folks at TC39 (the standards body that defines the syntax and semantics of ECMAScript) have introduced built-in modules with ECMAScript 6 (ES6).

幸运的是,TC39(定义ECMAScript语法和语义的标准机构)的精明人员已经引入了ECMAScript 6(ES6)内置模块。

ES6 offers up a variety of possibilities for importing and exporting modules which others have done a great job explaining — here are a few of those resources:

ES6提供了多种导入和导出模块的可能性,其他人则做了很好的解释-以下是其中的一些资源:

What’s great about ES6 modules relative to CommonJS or AMD is how it manages to offer the best of both worlds: compact and declarative syntax and asynchronous loading, plus added benefits like better support for cyclic dependencies.

与CommonJS或AMD相比,ES6模块最大的优点是它能够提供两全其美的优势:紧凑和声明性语法以及异步加载,以及诸如更好地支持循环依赖项等附加优点。

Probably my favorite feature of ES6 modules is that imports are live read-only views of the exports. (Compare this to CommonJS, where imports are copies of exports and consequently not alive).

我最喜欢的ES6模块功能是,导入是导出的实时只读视图。 (将此与CommonJS进行比较,CommonJS的进口是出口的副本,因此没有生命)。

Here’s an example of how that works:

这是一个如何工作的示例:

// lib/counter.js

var counter = 1;

function increment() {
  counter++;
}

function decrement() {
  counter--;
}

module.exports = {
  counter: counter,
  increment: increment,
  decrement: decrement
};


// src/main.js

var counter = require('../../lib/counter');

counter.increment();
console.log(counter.counter); // 1

In this example, we basically make two copies of the module: one when we export it, and one when we require it.

在此示例中,我们基本上制作了该模块的两个副本:一个在导出时复制,一个在需要时复制。

Moreover, the copy in main.js is now disconnected from the original module. That’s why even when we increment our counter it still returns 1 — because the counter variable that we imported is a disconnected copy of the counter variable from the module.

此外,现在main.js中的副本已与原始模块断开连接。 这就是为什么即使我们增加计数器也仍返回1的原因-因为导入的计数器变量是计数器变量与模块的断开连接副本。

So, incrementing the counter will increment it in the module, but won’t increment your copied version. The only way to modify the copied version of the counter variable is to do so manually:

因此,增加计数器将在模块中增加它,但不会增加您复制的版本。 修改计数器变量的复制版本的唯一方法是手动进行:

counter.counter++;
console.log(counter.counter); // 2

On the other hand, ES6 creates a live read-only view of the modules we import:

另一方面,ES6为导入的模块创建实时的只读视图:

// lib/counter.js
export let counter = 1;

export function increment() {
  counter++;
}

export function decrement() {
  counter--;
}


// src/main.js
import * as counter from '../../counter';

console.log(counter.counter); // 1
counter.increment();
console.log(counter.counter); // 2

Cool stuff, huh? What I find really compelling about live read-only views is how they allow you to split your modules into smaller pieces without losing functionality.

很酷的东西,对吧? 对于实时只读视图,我发现真正令人信服的是它们如何使您将模块拆分为较小的块而又不损失功能。

Then you can turn around and merge them again, no problem. It just “works.”

然后,您可以转身并再次合并它们,没问题。 它只是“有效”。

展望:捆绑模块 (Looking forward: bundling modules)

Wow! Where does the time go? That was a wild ride, but I sincerely hope it gave you a better understanding of modules in JavaScript.

哇! 时间去哪儿了? 那是一个疯狂的旅程,但是我衷心希望它能使您更好地了解JavaScript中的模块。

In the next section I’ll walk through module bundling, covering core topics including:

在下一节中,我将逐步介绍模块捆绑,涵盖以下核心主题:

  • Why we bundle modules

    为什么我们捆绑模块
  • Different approaches to bundling

    捆绑的不同方法
  • ECMAScript’s module loader API

    ECMAScript的模块加载器API
  • …and more. :)

    …和更多。 :)

NOTE: To keep things simple, I skipped over some of the nitty-gritty details (think: cyclic dependencies) in this post. If I left out anything important and/or fascinating, please let me know in the comments!

注意:为使事情简单,我跳过了本文中的一些实质性细节(认为:循环依赖项)。 如果我遗漏了任何重要和/或令人着迷的内容,请在评论中让我知道!

翻译自: https://www.freecodecamp.org/news/javascript-modules-a-beginner-s-guide-783f7d7a5fcc/

javascript模块

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值