包装库部分的代码构造是什么,它有什么用?

What is this code construct wrapping the parts of a library and what is it useful for?

我模仿了一个库,并能够编写以下代码。此代码创建了 'c' 对象,并为其分配了 'a' 函数。所以,要调用 'a',我必须写成 c.a().

此外,我能够向这个 'c' 对象添加更多功能。我想了解这段代码中发生了什么。它看起来不像普通的面向对象编程。这种 javascript 编程叫什么?

var c = (function(c) {
    if (c === undefined) {
        c = {};
    }

    function a() {
        alert(1);
    }
    c.a = a;
    return c;
}(c));

这是一个模块模式。您会看到该模式的许多变体,因此了解实际情况非常重要,您不能只模仿一个。

这段代码的重点是完成一个对象c(通常是您的全局库)。您的应用程序中可能有许多相似的代码片段,所有 c 的构建片段,可能每个片段都在其自己的文件中。

如果作为参数传递给函数的库对象 c 尚不存在 ( c === undefined ),则会创建它。这使得不依赖于执行顺序或预执行文件成为可能。

赋值的右边部分是一个IIFE(立即调用的函数表达式),即立即调用的函数。这种构造的优点是它创建了一个范围,可以在其中声明变量(例如 a 函数)而不会污染外部(全局)范围。这里的重点是没有实际意义,因为 a 无论如何都是外部化的,但模块通常依赖于几个内部(私有)函数和变量。

一个可能需要解释的细节:所有这些文件 看起来像 它们定义了一个新变量 c 但这里没有问题,即使文件是串联的: 如果 var 语句已经存在则不会定义新变量(变量是为整个范围定义的,这里是全局的,甚至在声明点之前)。

另一种写法是

var c = c || {}; // ensure the c variable is defined, and initialize its value it if necessary

(function() { // let's use an IIFE to have a protected scope and not pollute the global one
  function a() {
    alert(1);
  }
  c.a = a; // let's augment c
})();

这个可能比

更清楚
  • 它明确地将两个步骤分开(c 初始化和 c 使用 IIFE 完成)
  • 它不依赖于两个 c 同名变量
  • 它不那么冗长

这是相同的代码,但添加了注释,说明每一行的作用,以及当我们传递它时会发生什么。

//Here, we're defining a function that will return an object.
//its only parameter is named 'c'
//this is confusing, since the parameter has the same name as the global definition of the function.

//the var c definition is the global definition. the function parameter is not.
//so every reference to anything named 'c' inside the function definition is local. 
var c = (function(c) 
{
  //if c (the c we passed as a parameter) is not yet defined
  if (c === undefined) {
    //define c as an object
    c = {};
  }

  //define a function
  function a() {
    alert(1);
  }
  //attach it to the object
  c.a = a;

  //return the object
  return c;
}(c)); // call the constructor we just defined, using the global definition of `c`.
       // the first time we pass this point, c as a variable is still undefined.

为什么最后又写了(c))?

这个名字叫 immediately invoked function.

(function(received argument){

     //some code here.......

})(passed argument)  //<-- here the function is invoked 

c 是传递的参数。该函数在创建时立即被调用。这种类型的声明用于保持变量私有并保持全局命名空间干净。

您代码中的模式用于创建 modules

.......现在来你的代码:......

如果传递的参数未定义:................

首先,...}(c)) 立即调用函数的这一部分 invoked.It 传递了一个名为 c 的参数,该参数尚未定义。 (function(c){... 部分接收此 c 参数。

这里首先passed argument c是undefined.So if(c==undefined)被触发。此时使用c={}语句,undefined object c被赋值了一个empty object.

这里function a() { //... }是一个private方法,在module.It里面创建,不能全局访问。

私有方法 a 全球可用 通过使用 c.a=a statement.Thus 将其分配给 c 当对象将 return 您可以在全局上下文中调用此方法。

因此新创建的空对象 c 被分配一个名为 a 的方法。然后它 returns 和 var c 接收这个对象。

如果传递的参数不是未定义的:......

但是如果 passed cnot undefined 说,如果传递了一个对象,那么不会创建新对象。我的意思是如果 if(c==undefined) 是 falsy.So,它是not executed.I 表示没有新的空对象是 created.Then 传递的对象被分配了一个名为 a 的新方法,使用 c.a=a

就这么简单

下面的代码是您的代码的更简单版本。如果它最初是 undefined.So 它会自动发送一个空对象,你不必费心检查它是否未定义或 not.It 被称为 loose augmentation.

var c = (function(c) {

    function a() {
        alert(1);
    }
    c.a = a;
    return c;
}(c || {} ));

本文作者Ben Cherry helped me understand this type of pattern: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html

文章摘录:

匿名闭包

这是使这一切成为可能的基本结构,确实是 JavaScript 的最佳功能。我们将简单地创建一个匿名函数,并立即执行它。在函数内部运行的所有代码都在一个闭包中,它在我们的应用程序的整个生命周期中提供隐私和状态。

(function () {
    // ... all vars and functions are in this scope only
    // still maintains access to all globals
}());

注意匿名函数周围的 ()。这是语言所要求的,因为以标记函数开头的语句总是被认为是函数声明。包含 () 会创建一个函数表达式。

全球进口

JavaScript 有一个称为隐含全局的特性。每当使用一个名称时,解释器都会向后遍历作用域链,寻找该名称的 var 语句。如果找到 none,则假定该变量是全局变量。如果它在赋值中使用,则创建全局(如果它尚不存在)。这意味着在匿名闭包中使用或创建全局变量很容易。不幸的是,这会导致代码难以管理,因为(对人类而言)在给定文件中哪些变量是全局变量并不明显。

幸运的是,我们的匿名函数提供了一种简单的替代方法。通过将全局变量作为参数传递给我们的匿名函数,我们将它们导入到我们的代码中,这比隐含的全局变量更清晰、更快速。这是一个例子:

(function ($, YAHOO) {
    // now have access to globals jQuery (as $) and YAHOO in this code
}(jQuery, YAHOO));

模块导出

有时您不只是想使用全局变量,还想声明它们。我们可以通过使用匿名函数的 return 值导出它们来轻松地做到这一点。这样就完成了基本的模块模式,下面是一个完整的例子:

var MODULE = (function () {
    var my = {},
        privateVariable = 1;

    function privateMethod() {
        // ...
    }

    my.moduleProperty = 1;
    my.moduleMethod = function () {
        // ...
    };

    return my;
}());

请注意,我们已经声明了一个名为 MODULE 的全局模块,它具有两个 public 属性:一个名为 MODULE.moduleMethod 的方法和一个名为 MODULE.moduleProperty 的变量。此外,它使用匿名函数的闭包来维护私有内部状态。此外,我们可以使用上面学到的模式轻松导入所需的全局变量

你正在做的是声明一个匿名函数,然后用一个名为 c 的参数调用它,并将它分配给一个也称为 c 的变量,这非常令人困惑:-)

正在重命名变量,这就是您所拥有的:

var result=(function (input_parameter){...} (parameter_used_to_call_my_function));

你最后问的(c)是调用函数的参数。如果使用更长的语法,更容易看出:

var my_function=function(input_parameter){...};
var result=my_function(result);

还值得注意的是,你在调用my_function时使用result(虽然你称它为c)作为参数,这也是你刚才的变量名创建用于存储函数的 return 值。 JS 同意这一点,因为它对你如何处理变量并不严格,但这是一种令人困惑的编写代码的方式。您正在声明一个变量并将其(具有该名称的变量,此时不应该存在)作为参数传递给您的函数,以防万一它被较早声明(并在函数内部处理这种情况,至少是一致的)。

my_function里面发生的事情是你检查你的参数是否有一个以前的值(我在上一段中解释过);如果未定义,则将其初始化为空对象。然后将函数附加到 input_parameter 和 return 它。

我不知道这种类型的编程是否有名称,但对不同的事物使用相同的变量名看起来不是个好主意:-)

var c = (function(c) {
    if (c === undefined) {
        c = {};
    }

    function a() {
        alert(1);
    }
    c.a = a;
    return c;
}(c));

让我们一步一步来。

var c =

正在初始化一个名为 c 的变量。请注意,此时,如果名为 c 的变量已经初始化,c 将仅引用该值,直到我们到达此声明的末尾。

( .... )

这意味着里面的任何东西都应该被视为一个表达式。

function(c)

表示这个"expression"是一个接受参数的函数。此参数此后将以名称 c 引用,直到函数结束。 因此,在函数作用域外声明的任何名称为 c 的变量都不能在这里直接访问。虽然如果它在全局范围内,并且全局范围恰好是 window 对象,它可以称为 window.c.

if (c === undefined) { ... }

检查传递给的参数是否未定义。 return 如果未定义则为真,因此执行 if 块内的内容。

c = {}

将变量 c 设置为空对象。所以如果参数是(传递或)未定义的,我们在这里自己定义它(并且我们将它定义为一个空对象....)。

function a() { alert(1); }

声明了一个名为 a 调用的函数,它会导致警告数字 1。请注意,这只是一个函数声明。我们还没有调用函数。

c.a = a

参数 c 现在被分配了一个名为 a 的 属性,它引用了我们刚刚创建的函数 a

return c

以return值作为c的最终值的函数跳出,在我们对传递的参数进行更改后。

(fun...}(c))

调用我们刚刚创建的函数,并将 c 的当前值作为参数传递给它。由于我们将函数称为表达式,因此该表达式的结果将是函数的 return 值。我们的函数 return 是一个对象(我们传递给它的),在为它分配 属性 之后。

由于此表达式等同于变量 c,表达式的 return 值(即函数的 return 值)现在由变量保存c.

如果你正确阅读了所有这些内容,你会知道变量 c 现在将包含一个对象,该对象将有一个 属性 a 这是一个提醒数字 1。并且该对象还保留了它之前可能具有的属性。

如果我们仅通过使变量名称具有描述性来对这段代码进行去丑化处理以使其可读:

var myObject = (function(someObject) {
    if (someObject === undefined) {
        someObject = {};
    }
    function alertOne () {
        alert(1);
    }
    someObject.alertOne = alertOne;
    return someObject;
}(myObject));

这个节目是系列模块揭示模式的一集,它告诉我们如何以优雅的方式向先前声明的对象添加额外的属性,而不会污染全局范围。 主演立即调用的函数表达式 (IIFE)。