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

Atu*_*tul 39 javascript module-pattern

我模仿了一个库,并能够编写以下代码.此代码创建了分配功能的'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));
Run Code Online (Sandbox Code Playgroud)

Den*_*ret 42

这是一个模块模式.您将看到该模式的许多变体,因此了解真正发生的事情至关重要,您不能只模仿它.

这段代码的要点是完成一个对象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
})();
Run Code Online (Sandbox Code Playgroud)

这个可能更清楚了

  • 它明确地分离了两个步骤(使用IIFE c初始化和c完成)
  • 它不依赖于c具有相同名称的两个变量
  • 它不那么冗长

  • "污染全球范围",好听的短语 (5认同)
  • 我更喜欢这个答案,因为它也解释了**为什么**我想要使用它.作为一个纯粹的Node开发者,这种模式对我来说完全不为人知. (3认同)

Tim*_*ote 36

这是相同的代码,其中添加了关于每行的内容的注释,以及当我们传递它时会发生什么.

//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.
Run Code Online (Sandbox Code Playgroud)

  • 你能否指出哪个`c`s是全局的,哪些是本地的.特别是在`if(c === undefined){c = {}}`中 (5认同)
  • 简单干净!+1 (3认同)
  • 我觉得我需要为第一个评论段落投票.这既不是类式构造函数,也不是传递给它自己,也没有名字.这听起来好像你还没有理解自己发生了什么...... (2认同)

小智 13

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

    function a() {
        alert(1);
    }
    c.a = a;
    return c;
}(c));
Run Code Online (Sandbox Code Playgroud)

让我们一步一步来.

var c =

初始化一个名为c的变量.请注意,此时,如果已经初始化了名为c的变量,则c只有在我们到达此声明的末尾之前才会引用该值.

( .... )

这意味着内部的任何内容都应被视为表达式.

function(c)

意味着这个"表达式"是一个带参数的函数.此函数将由c函数引用,直到函数结束.c因此,在此处无法直接访问具有在函数范围之外声明的名称的任何变量.虽然它是在全局范围内,并且全局范围恰好是窗口对象,但它可以称为window.c.

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

检查传递给它的参数是否未定义.如果未定义则返回true,从而执行if块内的任何内容.

c = {}

将变量c设置为空对象.因此,如果参数是(传递或)未定义,我们自己在这里定义它(我们将它定义为空对象....).

function a() { alert(1); }

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

c.a = a

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

return c

c在经历了对传递的参数所做的更改之后,以返回值作为最终值的函数中断函数.

(fun...}(c))

调用我们刚刚创建的函数,并将其作为参数传递给它c.因为我们将函数称为表达式,所以此表达式的结果将是函数的返回值.并且我们的函数在为其分配属性后返回一个对象(我们传递给它).

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

如果你正确地阅读了所有这些内容,你就会知道变量c现在将拥有一个对象,该对象具有一个属性a,该属性是一个警告数字1的函数.该对象还保留了之前可能具有的属性.

如果我们通过使变量名称具有描述性来解除此代码以使其可读:

var myObject = (function(someObject) {
    if (someObject === undefined) {
        someObject = {};
    }
    function alertOne () {
        alert(1);
    }
    someObject.alertOne = alertOne;
    return someObject;
}(myObject));
Run Code Online (Sandbox Code Playgroud)

此节目是系列模块显示模式的一集,它告诉我们如何以优雅的方式向对象添加其他属性,而不会污染全局范围.主演立即调用函数表达式(IIFE).


AL-*_*ami 5

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

这是名为立即调用的函数.

(function(received argument){

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

})(passed argument)  //<-- here the function is invoked 
Run Code Online (Sandbox Code Playgroud)

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

代码中的模式用于创建模块.

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

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

首先,...}(c))调用立即调用的函数的这一部分.它与一个被调用的参数一起传递,该参数c尚未定义.(function(c){... 部分收到这个c论点.

这里首先passed argument c是undefined.So if(c==undefined)被触发.在这一点上使用c={}语句,未定义的对象c被赋值empty object.

function a() { //... }是在模块内创建的私有方法.无法全局访问.

私有方法 a是由全球范围内获得通过将其分配到用c c.a=astatement.Thus当对象将返回您可以拨打全球范围内的这种方法.

因此,为新创建的空对象c分配了一个名为的方法a.然后它返回并var c接收该对象.

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

但是,如果passed cnot undefined说,如果一个对象通过,则没有新的对象被创建.我的意思是,如果if(c==undefined)是falsy.So,它不是executed.I意味着没有新的空对象created.Then传递的对象被分配了一个所谓的新方法a使用c.a=a

这很简单.

下面的代码是更简单的代码版本.如果它最初是未定义的,它将自动发送一个空对象.所以你不必麻烦地检查它是否未定义.它被称为松散增强.

var c = (function(c) {

    function a() {
        alert(1);
    }
    c.a = a;
    return c;
}(c || {} ));
Run Code Online (Sandbox Code Playgroud)