65.9K
CodeProject 正在变化。 阅读更多。
Home

JavaScript 中的模块和揭示模块模式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (8投票s)

2017 年 1 月 5 日

CPOL

4分钟阅读

viewsIcon

14521

用简单的语言解释 JavaScript 中的模块和揭示模块模式

这是关于 JavaScript 作用域管理的系列文章中的第二篇。在第一篇文章中,我详细讨论了立即调用的函数表达式 (IIFE)。如果你不熟悉 IIFE 并且还没有机会阅读前一篇文章,我建议你在继续阅读之前先阅读那一篇

这篇文章将重点介绍 JavaScript 中的模块和揭示模块模式。当我们想到面向对象编程时,首先想到的是类。什么是类?简单来说,类是变量和方法的封装。类可以有public(公共)和private(私有)成员。根据你想向类外部公开哪些信息,你可以将相关的变量和方法设为public,而将不应公开的内容设为private

JavaScript 是一种面向对象的语言。但 JavaScript 默认不支持private变量和函数。然而,有一些方法可以在语言中实现相同的private-public结构。默认情况下,JavaScript 中的任何函数都分配有全局作用域。看下面的函数

function keepMePrivate() {
   console.log("Let others not bother what I do!");
}

函数keepMePrivate可以从任何地方调用,并且是全局可访问的。在某些情况下,你可能希望将一些函数(甚至变量)设为private。这时模块模式就派上用场了。看看下面的代码

var module = (function() {
   console.log("You have started learning about a Module");
}());

你一定还记得我们在上一篇文章中学到的 IIFE 模式。我声明了一个 IIFE,它向浏览器的控制台写入一个简单的消息。IIFE 创建了一个局部作用域,并将其中所有的变量和函数保持为private。然后,我们只能将那些我们想要公开的变量和函数返回给外部世界。我将 IIFE 赋值给一个变量module。这样做,我创建了一个全局可访问的模块。但是,目前这个模块没什么用。它将逐渐演变成一些真实可用的东西。

var module = (function() {
   var privateVar = "Stop thinking about me dear foreigners";
   var privateFunc = function() {
      console.log("You are now learning how to create private functions.");
   };
}());

现在我们有一个变量privateVar和一个函数privateFunc,它们对于 IIFE 块来说是private的。任何在外部尝试使用它们的行为都不是应受惩罚的罪过 :) 但肯定会抛出错误,导致你的 JavaScript 代码中断。我们的模块仍然无用,因为我们还没有从 IIFE 块返回任何东西。我们继续。

var module = (function() {
   var privateFunc = function() {
      console.log("I'm private. Only my family knows what I do.");
   }
   return {
      publicVar: "Good things are available to good people.",
      publicFunc: function() {
         privateFunc();
         console.log("Keep focused and learn to create public functions");
      }
   };
}());

我们已经达到了一个拥有工作模块的程度。上面的 IIFE 返回一个对象,其中publicVar作为属性,publicFunc作为方法。这就是所谓的创建对象的字面量表示法。你可以在我关于JavaScript 对象的文章中阅读更多关于对象字面量的信息。

返回的对象被赋值给变量module。函数privateFunc可以在publicFunc内部访问。IIFE 外部的任何代码都不能直接调用privateFunc。可以通过点号表示法调用返回对象的成员,如下所示

var someVar = module.publicVar;
module.publicFunc();

上面的 IIFE 返回一个匿名对象。还有其他方法可以实现相同的功能。下面这种方法称为命名局部对象字面量。

var module = (function() {
   var privateFunc = function() {
      console.log("I'm private. Only my family knows what I do.");
   }

   var myObj = {};
   myObj.publicVar = "Good things are available to good people.";
   myObj.publicFunc = function() {
      privateFunc();
      console.log("Keep focused and learn to create public functions");
   }
   return myObj;
}());

我们首先创建了一个空对象myObj,然后稍后添加了属性publicVar和方法publicFunc。最后,我们返回命名对象myObj。当你的模块中有大量代码时,并且你想清楚地看到哪些是public成员,而无需查看return语句时,这很有用。

下面展示了这个模式的一个小变体,我们在定义命名对象本身时,将所有public成员放入对象中。最后,对象按惯例返回。

var module = (function() {
   var myObj = {
      publicVar: "Good things are available to good people.",
      publicFunc: function() {
         console.log("Keep focused and learn to create public functions");
      }
   };
   return myObj;
}());

到目前为止我们看到的就是所谓的模块模式。它有一个改进版本,称为揭示模块模式。我们接下来看它。

揭示模块模式

揭示模块模式允许你以传统的 JavaScript 方式定义变量和函数,并在最后提供指定public成员的机制。基本上,我们将所有属性和方法定义为具有private模块级作用域,并返回一个匿名对象,其属性是指向private成员的指针。请看下面的说明

var revealingModule = (function() {
   var privateVar = "Keep me private";
   var publicVar = "Return me as public";

   function privateFunc() {
      console.log("A private function");
   }

   function publicFunc1() {
      console.log("First public function");
   }

   function publicFunc2() {
      console.log("Second public function");
   }

   return {
      publicProperty: publicVar,
      firstPublicMethod: publicFunc1,
      secondPublicMethod: publicFunc2
   };
}());

这是一种非常简洁地指定你想向外部世界公开的public成员的方法。该模式的主要优点是代码的可读性。你可以很容易地在return语句中找出公开的变量和函数。你可以根据自己的喜好为返回对象的属性和方法命名。

当我们想在 JavaScript 中管理作用域时,模块和揭示模块模式非常有用。让我们通过另一个例子来理解这一点。

var rectangle = (function() { 
   function getArea(length, breadth) {
      return length*breadth;
   }
 
   function getPerimeter(length, breadth) {
      return 2*(length + breadth);
   }
 
   return {
      GetArea: getArea,
      GetPerimeter: getPerimeter
   };
}());

我们正在创建一个名为rectangle的模块,它有两个private方法getAreagetPerimeter。这两个方法都应该是不言自明的。我们返回一个对象,其中包含两个属性GetAreaGetPerimeter,它们分别包含函数getAreagetPerimeter。包含函数的属性称为方法。我们可以使用变量rectangle调用方法GetAreaGetPerimeter,如下所示。

var area = rectangle.GetArea(2, 3); // area = 6
var perimeter = rectangle.GetPerimeter(2, 3); // perimeter = 10

使用揭示模块模式为private实现提供抽象。这就像向外部世界公开public API,同时将实现细节保留为private

你喜欢这篇文章吗?请在评论框中留下你的评论、问题或建议,让我听到你的声音。感谢阅读。

热爱 JavaScript 并想进一步探索这门语言?请访问我的博客 www.code-morning.com

© . All rights reserved.