使用匿名函数的JavaScript封装

分享于 

12分钟阅读

Web开发

  繁體 雙語

介绍

开发现代软件可能会成为一个非常复杂的业务。 使用面向对象编程技术,降低复杂性的核心原则之一是封装的使用。 通过隐藏 private 数据和函数 inside 对象( 一种称为封装的过程),减少对象之间的可以能交互,降低了代码的复杂性。

在诸如C。C++ 和 C# 封装的语言中,使用 privateprotectedpublicinternal 等关键字构建了语言。 但是,在JavaScript中,不存在这样的关键字,因此无法轻松实现封装。

但是,使用匿名函数为JavaScript对象实现至少 publicprivate 作用域是一种机制。 本文的目的是允许用户在JavaScript中定义和使用像对象这样的类,这可以是,。

  • 使用函数如函数创建
  • 可以有 publicprivate 成员
  • 可以有多个实例,每个实例都包含自己的private 作用域
  • 将封装对象的内部工作

匿名函数

在JavaScript中,程序员可以定义匿名函数,这些函数在加载后被自动执行。 执行这里操作的标准方法是 below。

(function () {
 // Code here} ());

在标记为'这里代码'的节中,我们可以根据需要定义多个 private 函数和变量。 由于代码是执行( 因为'()'最后一行的部分),所以我们还可以在需要时包含执行函数的。

例如...

(function () {
 // Define a function Function HiddenFunction() {
 }
 // Declare a variablevar variable = {};
 // Execute a function HiddenFunction();
} ());

。loaded加载时执行方法'HiddenFunction'。

匿名函数的目的只是定义和执行一些代码,但重要的是,包含 inside的变量和函数不可以见。 即变量和函数是匿名函数的private,这是我们可以利用来提供对象封装的特性。

创建构造函数函数

本文的第一个目标是有一个对象,它可以使用函数类似函数创建。 在前一节中,我们看到我们可以在匿名函数中定义 private 函数;但是如何定义函数类似于外界。

要解决这一问题,首先必须将变量传入匿名函数,以便我们将构造函数公开到外部世界。 我们可以通过重新定义匿名函数的定义来做到这一点。

(function (window) {
} (window));

浏览器对象模型( 物料清单)的'window'参数部分,它允许JavaScript与浏览器进行通信。 为了将构造函数添加到这个模型中,我们的意图是在我们的JavaScript代码中。 这允许我们将我们的功能导出到外部世界。

例如,假设我们想创建一个名为'Instance'的类,并且希望向BOM公开这个类,我们可以用下面的代码实现。

(function (window) {
 function Instance() {
 }
 window.Instance = Instance;
} (window));

代码行'window.Instance'使用 NAME'Instance'将本地方法'Instance'公开到 BOM。

完成之后,我们可以使用下面的代码创建对象的多个实例。

var instance1 = new Instance();var instance2 = new Instance();

在这个阶段定义了对象,可以创建对象的多个实例,但是对象不包含任何 public 访问函数或者内部变量。 这将在以后完成。

公开 public 访问功能

以前创建的对象不包含任何方法供用户调用。 为此,我们必须在匿名函数中定义访问方法,然后将它们添加到构造函数方法的'Prototype'。

例如假设要添加名为'Set'的public 访问函数,这可以通过使用下面的代码来完成。

(function (window) {
 function Instance() {
 }
 window.Instance = Instance;
 Instance.prototype.Set = function (newValue) {
 // Implementation code here };
} (window));

定义 上面 向 Instance 对象添加一个名为'Set'的public 访问函数。 Instance 对象的用户可以调用这里方法来执行所需的操作。

在这个阶段定义了对象,可以创建对象的多个实例,并且对象包含所需的public 访问函数。 但是,目前它不包含任何内部变量,因此'Set'方法无法执行任何操作。

添加实例特定数据

我们可以创建对象的多个实例,但是我们没有对象来包含实例特定数据,现在不能区分对象的多个实例。

我们类的构造函数函数是'Instance'函数并创建实例特定数据( 变量),我们必须在这个函数中定义一个对象来包含我们需要的实例变量。 这里外,我们需要将实例变量与所创建的对象实例相关联;但是我们不希望将变量直接附加到对象实例。

为解决这个问题,我们将定义一个独特的marker inside 变量 block。 我们还将设置创建的对象的id,以便它具有对变量 block的引用。 另外,我们将在内部存储变量 block,使用id作为密钥,这样我们以后可以检索它。

下面的代码演示显示的逻辑的实现 上面。

(function (window) {
 function Instance() {
 // Create a new variable block for the new object instancevar variables = {
 // Define a unique id to identify the new object instance id: new Date().getTime(),
 // Define variables here... };
 // Assign the unique id to new object instance so we can use// it to get back to the variables for the new object instancethis.id = variables.id;
 // Store the variable block for later variableStore[this.id] = variables;
 }
 // Variables for object instancesvar variableStore = {};
} (window));

使用这个逻辑,public 访问方法现在可以使用附加的id来获得对象变量的正确实例,如下所示。

(function (window) {
 Instance.prototype.Set = function (newValue) {
 var variables = variableStore[this.id];
 // Perform the change here! };
} (window));

连接各个部分

在这个阶段,我们探索了使用匿名函数封装函数和变量 inside JavaScript所需的所有逻辑。 但是,要清楚地说明,我们需要看到一个具体的例子。

以下代码实现了类类,该类封装单个 private 变量('value')。 此外,它只公开了两个 public 方法,称为'Set'和'Get'。 JavaScript对象中的其余逻辑仍然隐藏于用户。

(function (window) {
 function Instance() {
 // Create a new variable block for the new object instancevar variables = {
 // Define a unique id to identify the new object instance id: new Date().getTime(),
 // Define variables for the new object instance value: 0 };
 // Assign the unique id to new object instance so we can use// it to get back to the variables for the new object instancethis.id = variables.id;
 // Store the variable block for later variableStore[this.id] = variables;
 }
 window.Instance = Instance;
 // Variables for object instancesvar variableStore = {};
 // Public methods Instance.prototype.Set = function (newValue) {
 Set(variableStore[this.id], newValue);
 };
 Instance.prototype.Get = function () {
 return Get(variableStore[this.id]);
 };
 // Private methodsfunction Set(variables, newValue) {
 variables.value = newValue;
 };
 function Get(variables) {
 return variables.value;
 };
} (window));

此外,可以使用以下测试代码验证对象的预期逻辑。

(function (window) {
 function AreEqual(actual, expected, error) {
 if (actual!= expected) {
 alert(error);
 }
 };
 //var instance1 = new Instance();
 var instance2 = new Instance();
 AreEqual(instance1.Get(), 0, "Instance1 should equal 0");
 AreEqual(instance2.Get(), 0, "Instance2 should equal 0");
 instance1.Set(10);
 AreEqual(instance1.Get(), 10, "Instance1 should equal 10");
 AreEqual(instance2.Get(), 0, "Instance2 should equal 0");
 instance2.Set(20);
 AreEqual(instance1.Get(), 10, "Instance1 should equal 10");
 AreEqual(instance2.Get(), 20, "Instance2 should equal 20");
 instance1.Set(11);
 AreEqual(instance1.Get(), 11, "Instance1 should equal 11");
 AreEqual(instance2.Get(), 20, "Instance2 should equal 20");
 instance2.Set(22);
 AreEqual(instance1.Get(), 11, "Instance1 should equal 11");
 AreEqual(instance2.Get(), 22, "Instance2 should equal 22");
} (window));

你自己试试吧

我已经向 Visual Studio 2010项目添加了示例代码,以及一个用于加载JavaScript文件的HTML文件。 项目包含下列文件。

  • HTMLPage.htm
  • Instance.js
  • TestInstance.js

HTML页面用于启动项目( 当按F5时,应该是活动窗口)。 它的目的是简单地加载两个JavaScript文件。

文件" Instance.js"包含示例实现,它展示了如何使用匿名函数来封装实现细节。

文件" TestInstance.js"调用示例实现,你可以使用这里文件插入断点以便调试。 在执行过程中,你将能够看到使用匿名函数实际上封装了对象( 除了 id marker )的几乎所有实现细节。

结束语

本文表明,使用匿名函数可以成功地封装JavaScript对象。 然而,这里给出的定义并非完全是完整的。 例如对象id仍然可见,当它应该隐藏时。

这里外,这里提供的代码只是JavaScript封装的框架,并且很好地看到了这项工作,以提供继承。

历史记录

  • 2014-04-10首次修订