Javascript立即调用函数模式

时间:2012-06-11 17:18:03

标签: javascript function design-patterns

你怎么称呼这些模式?他们之间有什么区别?你什么时候用?还有其他类似的模式吗?

(function() {
    console.log(this);  // window
})();

(function x() {
    console.log(this);  // window
})();

var y = (function() {
    console.log(this);  // window
})();

var z = function() {
    console.log(this);  // window
}();

编辑:我刚刚通过命名最后两种情况中的函数找到了两种看似多余的方法...

var a = (function foo() {
    console.log(this);  // window
})();

var b = function bar() {
    console.log(this);
}();

EDIT2:以下是@GraceShao提供的另一种模式,它使函数可以在函数范围之外访问。

(x = function () {
    console.log(this);  // window
    console.log(x);     // function x() {}
})();
console.log(x);         // function x() {}

// I played with this as well 
// by naming the inside function 
// and got the following:

(foo = function bar() {
    console.log(this);  // window
    console.log(foo);   // function bar() {}
    console.log(bar);   // function bar() {}
})();
console.log(foo);       // function bar() {}
console.log(bar);       // undefined

5 个答案:

答案 0 :(得分:35)

以下是您的函数,其中一些注释描述了它们可能有用的时间/原因:

(function() {
    // Create a new scope to avoid exposing variables that don't need to be
    // This function is executed once immediately
})();

(function fact(i) {
    // This named immediately invoked function is a nice way to start off recursion
    return i <= 1 ? 1 : i*fact(i - 1);
})(10);

var y = (function() {
    // Same as the first one, but the return value of this function is assigned to y
    return "y's value";
})();

var z = function() {
    // This is the exact same thing as above (except it's assigned to z instead of y, of course).
    // The parenthesis in the above example don't do anything since this is already an expression
}();

答案 1 :(得分:6)

在这种情况下,它们在语义上都是相同的。 The ECMAScript specification包含完整的生产规则,因此这是一个严格的简化。

另请注意,我忽略了命名函数的名称(x),因为名称未被使用;它可以在正文中引用 ,但由于它是FunctionExpression(通过语法生成),它永远不会(在正确的 JS实现中)污染包含范围 - 见评论。

(function() {
    console.log(this);  // window
})();

(function x() {
    console.log(this);  // window
})();

var y = (function() {
    console.log(this);  // window
})();

var z = function() {
    console.log(this);  // window
}();

减少(在这种情况下,身体无关紧要,它们都“返回未定义”):

(function() {})();

(function x() {})();

var y = (function() {})();

var z = function() {}();

减少(在ECMAScript语法FunctionExpression中是一个生产规则,但在这里我用它来表示“一个函数的表达式”):

FunctionExpression()

FunctionExpression()

var y = FunctionExpression()

var z = FunctionExpression()

忽略结果的赋值(总是undefined),可以看出所有形式都是相同的。

快乐的编码。

答案 2 :(得分:2)

自行调用匿名功能。函数体将立即被调用。

(function() {
    console.log(this);  // window
})();

自我调用功能。函数体将立即被调用。您仍然可以参考函数体内的函数x。因此,当您想立即执行某些操作,然后您可能想要迭代它时,您可以直接引用它。

(function x() {
    console.log(this);  // window
    console.log(x);     // function x() {}
})();

将立即调用右侧的自调用匿名函数,并将返回的值分配给y。通常在使用此模式时它具有返回值,否则,y将为undefined

var y = (function() {
    console.log(this);  // window
})();

IMO,它与第三个相同。包含该函数的第3个括号只是为了使函数看起来像一个整体。但两者的功能是相同的。

var z = function() {
    console.log(this);  // window
}();

与第二个类似,但您可以使用以下函数引用函数范围外的x:

(x = function () {
    console.log(this);  // window
    console.log(x);     // function x() {}
})();
console.log(x);         // function x() {}

答案 3 :(得分:0)

(function(){     'use strict'; 您可以使用此类型

为什么?:IIFE-立即调用的函数表达式从全局范围中删除变量。这有助于防止变量和函数声明在全局范围内的生存时间超过预期,这也有助于避免可变冲突。

为什么?:当您的代码缩小并捆绑到单个文件中以部署到生产服务器时,您可能会发生变量冲突和许多全局变量。 IIFE通过为每个文件提供可变范围来保护您免受这两种情况的影响。

答案 4 :(得分:0)

是时候使用ES06了,以下是使用ES06箭头功能的功能。

 (() => {
    // Create a new scope to avoid exposing variables that don't need to be
    // This function is executed once immediately
})();

(fact = (i)=>(
  // This named immediately invoked function is a nice way to start off recursion
  i <= 1 ? 1 : i*fact(i - 1)
))(10)

const y = (() => (
    // Same as the first one, but the return value of this function is assigned to y
     "y's value"
))();

const z = (() => {
    // This is the exact same thing as above (except it's assigned to z instead of y, of course).
    // The parenthesis in the above example don't do anything since this is already an expression
})();