围绕对象/函数/类声明的圆括号是什么意思?(复制)

时间:2022-08-26 23:23:12

This question already has an answer here:

这个问题已经有了答案:

I'm new to both JavaScript and YUI. In YUI library examples, you can find many uses of this construct:

我对JavaScript和YUI都不熟悉。在YUI库示例中,您可以找到这个构造的许多用途:

(function() {
    var Dom = YAHOO.util.Dom,
    Event = YAHOO.util.Event,
    layout = null,
        ...
})();

I think the last couple of parentheses are to execute the function just after the declaration.

我认为最后两个括号是在声明之后执行函数。

... But what about the previous set of parentheses surrounding the function declaration?

…但是关于函数声明的前一组圆括号呢?

I think it is a matter of scope; that's to hide inside variables to outside functions and possibly global objects. Is it? More generally, what are the mechanics of those parentheses?

我认为这是一个范围问题;这是为了隐藏变量到外部函数或者全局对象。是吗?更一般地说,圆括号的结构是什么?

7 个解决方案

#1


198  

It is a self-executing anonymous function. The first set of parentheses contain the expressions to be executed, and the second set of parentheses executes those expressions.

它是一个自执行的匿名函数。第一组圆括号包含要执行的表达式,第二组圆括号执行这些表达式。

It is a useful construct when trying to hide variables from the parent namespace. All the code within the function is contained in the private scope of the function, meaning it can't be accessed at all from outside the function, making it truly private.

当试图从父名称空间中隐藏变量时,它是一个有用的构造。函数内的所有代码都包含在函数的私有范围中,这意味着它不能从函数外部访问,这使它成为真正的私有。

See:

看到的:

http://en.wikipedia.org/wiki/Closure_%28computer_science%29

http://en.wikipedia.org/wiki/Closure_%28computer_science%29

http://peter.michaux.ca/articles/javascript-namespacing

http://peter.michaux.ca/articles/javascript-namespacing

#2


130  

Andy Hume pretty much gave the answer, I just want to add a few more details.

安迪·休谟差不多给出了答案,我只是想补充一些细节。

With this construct you are creating an anonymous function with its own evaluation environment or closure, and then you immediately evaluate it. The nice thing about this is that you can access the variables declared before the anonymous function, and you can use local variables inside this function without accidentally overwriting an existing variable.

使用这个构造,您正在创建一个具有自己的评估环境或闭包的匿名函数,然后您立即对它进行评估。这样做的好处是,您可以访问匿名函数之前声明的变量,并且可以在这个函数中使用局部变量,而不会意外地覆盖现有的变量。

The use of the var keyword is very important, because in JavaScript every variable is global by default, but with the keyword you create a new, lexically scoped variable, that is, it is visible by the code between the two braces. In your example, you are essentially creating short aliases to the objects in the YUI library, but it has more powerful uses.

var关键字的使用非常重要,因为在JavaScript中,默认情况下每个变量都是全局的,但是对于关键字,您可以创建一个新的、词汇范围的变量,也就是说,两个大括号之间的代码可以看到它。在您的示例中,您实际上是在为YUI库中的对象创建简短的别名,但是它有更强大的用途。

I don't want to leave you without a code example, so I'll put here a simple example to illustrate a closure:

我不想让你们没有一个代码示例,所以我在这里举一个简单的例子来说明一个闭包:

var add_gen = function(n) {
  return function(x) {
    return n + x;
  };
};
var add2 = add_gen(2);
add2(3); // result is 5

What is going on here? In the function add_gen you are creating an another function which will simply add the number n to its argument. The trick is that in the variables defined in the function parameter list act as lexically scoped variables, like the ones defined with var.

这是怎么回事?在函数add_gen中,您正在创建另一个函数,它将简单地将数字n添加到它的参数中。诀窍在于,在函数参数列表中定义的变量充当词法作用域的变量,就像用var定义的变量一样。

The returned function is defined between the braces of the add_gen function so it will have access to the value of n even after add_gen function has finished executing, that is why you will get 5 when executing the last line of the example.

返回的函数是在add_gen函数的大括号中定义的,因此即使在add_gen函数完成执行之后,它也可以访问n的值,这就是为什么在执行示例的最后一行时,您会得到5。

With the help of function parameters being lexically scoped, you can work around the "problems" arising from using loop variables in anonymous functions. Take a simple example:

通过对函数参数进行词法作用域的帮助,您可以解决在匿名函数中使用循环变量所引起的“问题”。以一个简单的例子:

for(var i=0; i<5; i++) {
  setTimeout(function(){alert(i)}, 10);
}

The "expected" result could be the numbers from zero to four, but you get four instances of fives instead. This happens because the anonymous function in setTimeout and the for loop are using the very same i variable, so by the time the functions get evaluated, i will be 5.

“预期”结果可能是从0到4,但您将得到4个5实例。这是因为setTimeout中的匿名函数和for循环使用的是完全相同的i变量,所以当函数被求值时,i将是5。

You can get the naively expected result by using the technique in your question and the fact, that function parameters are lexically scoped. (I've used this approach in an other answer)

您可以通过在您的问题中使用技术来获得天真的预期结果,而且事实上,函数参数是在词汇范围内的。(我在另一个回答中使用了这个方法)

for(var i=0; i<5; i++) {
  setTimeout(
     (function(j) {
       return function(){alert(j)};
     })(i), 10);
}

With the immediate evaluation of the outer function you are creating a completely independent variable named j in each iteration, and the current value of i will be copied in to this variable, so you will get the result what was naively expected from the first try.

通过对外部函数的即时评估,你在每次迭代中创建一个完全独立的变量j,并且我的当前值将被复制到这个变量中,这样你就会得到第一次尝试所期望的结果。

I suggest you to try to understand the excellent tutorial at http://ejohn.org/apps/learn/ to understand closures better, that is where I learnt very-very much.

我建议您尝试理解http://ejohn.org/apps/learn/上的优秀教程,以便更好地理解闭包,这正是我学到的非常多。

#3


46  

...but what about the previous round parenteses surrounding all the function declaration?

…但是,在所有功能声明的周围,前一轮的parenteses又如何呢?

Specifically, it makes JavaScript interpret the 'function() {...}' construct as an inline anonymous function expression. If you omitted the brackets:

具体来说,它使JavaScript解释'function(){…}构造为内联匿名函数表达式。如果省略括号:

function() {
    alert('hello');
}();

You'd get a syntax error, because the JS parser would see the 'function' keyword and assume you're starting a function statement of the form:

你会得到一个语法错误,因为JS解析器会看到“function”关键字,并假设您正在启动表单的函数语句:

function doSomething() {
}

...and you can't have a function statement without a function name.

…没有函数名就不能有函数语句。

function expressions and function statements are two different constructs which are handled in very different ways. Unfortunately the syntax is almost identical, so it's not just confusing to the programmer, even the parser has difficulty telling which you mean!

函数表达式和函数语句是两种不同的结构,它们的处理方式非常不同。不幸的是,语法几乎是相同的,所以这不仅使程序员感到困惑,甚至解析器也难以说明您的意思!

#4


14  

Juts to follow up on what Andy Hume and others have said:

继续追踪安迪·休谟和其他人所说的话:

The '()' surrounding the anonymous function is the 'grouping operator' as defined in section 11.1.6 of the ECMA spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf.

围绕匿名函数的“()”是ECMA规范第11.1.6节中定义的“分组操作符”:http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf。

Taken verbatim from the docs:

从文件中逐字记录:

11.1.6 The Grouping Operator

11.1.6分组操作符

The production PrimaryExpression : ( Expression ) is evaluated as follows:

(表达式)的值计算如下:

  1. Return the result of evaluating Expression. This may be of type Reference.
  2. 返回表达式求值的结果。这可能是类型引用。

In this context the function is treated as an expression.

在此上下文中,函数被视为表达式。

#5


5  

A few considerations on the subject:

关于这个问题的一些考虑:

  • The parenthesis:

    括号:

    The browser (engine/parser) associates the keyword function with

    浏览器(引擎/解析器)将关键字函数与

    [optional name]([optional parameters]){...code...}
    

    So in an expression like function(){}() the last parenthesis makes no sense.

    因此,在函数(){}()的表达式中,最后一个括号没有意义。

    Now think at

    现在想在

    name=function(){} ; name() !?
    

Yes, the first pair of parenthesis force the anonymous function to turn into a variable (stored expression) and the second launches evaluation/execution, so ( function(){} )() makes sense.

是的,第一对括号强制匿名函数转换为变量(存储表达式),第二个括号启动计算/执行,因此(function(){})()是有意义的。

  • The utility: ?

    用途:?

    1. For executing some code on load and isolate the used variables from the rest of the page especially when name conflicts are possible;

      在加载时执行一些代码并将使用的变量与页面的其他部分隔离,特别是在可能出现名称冲突时;

    2. Replace eval("string") with

      取代eval(“字符串”)

      (new Function("string"))()

      (新功能(“字符串”))()

    3. Wrap long code for " =?: " operator like:

      为“=?”包装长代码。:“运营商:

      result = exp_to_test ? (function(){... long_code ...})() : (function(){...})();

      结果= exp_to_test ?(函数(){…long_code…})():(函数(){…})();

#6


3  

The first parentheses are for, if you will, order of operations. The 'result' of the set of parentheses surrounding the function definition is the function itself which, indeed, the second set of parentheses executes.

第一个括号表示操作的顺序。围绕函数定义的圆括号集合的“结果”是函数本身,实际上,第二组圆括号是执行的。

As to why it's useful, I'm not enough of a JavaScript wizard to have any idea. :P

至于它为什么有用,我对JavaScript向导还不了解。:P

#7


1  

See this question. The first set of parenthesis aren't necessary if you use a function name, but a nameless function requires this construct and the parenthesis serve for coders to realize that they've viewing a self-invoking function when browsing the code (see one blogger's best-practices recommendation).

看到这个问题。如果您使用函数名,那么第一个括号是不必要的,但是一个无名的函数需要这个构造,而圆括号则服务于编码器,以实现在浏览代码时查看自调用函数(参见一个blogger的最佳实践推荐)。

#1


198  

It is a self-executing anonymous function. The first set of parentheses contain the expressions to be executed, and the second set of parentheses executes those expressions.

它是一个自执行的匿名函数。第一组圆括号包含要执行的表达式,第二组圆括号执行这些表达式。

It is a useful construct when trying to hide variables from the parent namespace. All the code within the function is contained in the private scope of the function, meaning it can't be accessed at all from outside the function, making it truly private.

当试图从父名称空间中隐藏变量时,它是一个有用的构造。函数内的所有代码都包含在函数的私有范围中,这意味着它不能从函数外部访问,这使它成为真正的私有。

See:

看到的:

http://en.wikipedia.org/wiki/Closure_%28computer_science%29

http://en.wikipedia.org/wiki/Closure_%28computer_science%29

http://peter.michaux.ca/articles/javascript-namespacing

http://peter.michaux.ca/articles/javascript-namespacing

#2


130  

Andy Hume pretty much gave the answer, I just want to add a few more details.

安迪·休谟差不多给出了答案,我只是想补充一些细节。

With this construct you are creating an anonymous function with its own evaluation environment or closure, and then you immediately evaluate it. The nice thing about this is that you can access the variables declared before the anonymous function, and you can use local variables inside this function without accidentally overwriting an existing variable.

使用这个构造,您正在创建一个具有自己的评估环境或闭包的匿名函数,然后您立即对它进行评估。这样做的好处是,您可以访问匿名函数之前声明的变量,并且可以在这个函数中使用局部变量,而不会意外地覆盖现有的变量。

The use of the var keyword is very important, because in JavaScript every variable is global by default, but with the keyword you create a new, lexically scoped variable, that is, it is visible by the code between the two braces. In your example, you are essentially creating short aliases to the objects in the YUI library, but it has more powerful uses.

var关键字的使用非常重要,因为在JavaScript中,默认情况下每个变量都是全局的,但是对于关键字,您可以创建一个新的、词汇范围的变量,也就是说,两个大括号之间的代码可以看到它。在您的示例中,您实际上是在为YUI库中的对象创建简短的别名,但是它有更强大的用途。

I don't want to leave you without a code example, so I'll put here a simple example to illustrate a closure:

我不想让你们没有一个代码示例,所以我在这里举一个简单的例子来说明一个闭包:

var add_gen = function(n) {
  return function(x) {
    return n + x;
  };
};
var add2 = add_gen(2);
add2(3); // result is 5

What is going on here? In the function add_gen you are creating an another function which will simply add the number n to its argument. The trick is that in the variables defined in the function parameter list act as lexically scoped variables, like the ones defined with var.

这是怎么回事?在函数add_gen中,您正在创建另一个函数,它将简单地将数字n添加到它的参数中。诀窍在于,在函数参数列表中定义的变量充当词法作用域的变量,就像用var定义的变量一样。

The returned function is defined between the braces of the add_gen function so it will have access to the value of n even after add_gen function has finished executing, that is why you will get 5 when executing the last line of the example.

返回的函数是在add_gen函数的大括号中定义的,因此即使在add_gen函数完成执行之后,它也可以访问n的值,这就是为什么在执行示例的最后一行时,您会得到5。

With the help of function parameters being lexically scoped, you can work around the "problems" arising from using loop variables in anonymous functions. Take a simple example:

通过对函数参数进行词法作用域的帮助,您可以解决在匿名函数中使用循环变量所引起的“问题”。以一个简单的例子:

for(var i=0; i<5; i++) {
  setTimeout(function(){alert(i)}, 10);
}

The "expected" result could be the numbers from zero to four, but you get four instances of fives instead. This happens because the anonymous function in setTimeout and the for loop are using the very same i variable, so by the time the functions get evaluated, i will be 5.

“预期”结果可能是从0到4,但您将得到4个5实例。这是因为setTimeout中的匿名函数和for循环使用的是完全相同的i变量,所以当函数被求值时,i将是5。

You can get the naively expected result by using the technique in your question and the fact, that function parameters are lexically scoped. (I've used this approach in an other answer)

您可以通过在您的问题中使用技术来获得天真的预期结果,而且事实上,函数参数是在词汇范围内的。(我在另一个回答中使用了这个方法)

for(var i=0; i<5; i++) {
  setTimeout(
     (function(j) {
       return function(){alert(j)};
     })(i), 10);
}

With the immediate evaluation of the outer function you are creating a completely independent variable named j in each iteration, and the current value of i will be copied in to this variable, so you will get the result what was naively expected from the first try.

通过对外部函数的即时评估,你在每次迭代中创建一个完全独立的变量j,并且我的当前值将被复制到这个变量中,这样你就会得到第一次尝试所期望的结果。

I suggest you to try to understand the excellent tutorial at http://ejohn.org/apps/learn/ to understand closures better, that is where I learnt very-very much.

我建议您尝试理解http://ejohn.org/apps/learn/上的优秀教程,以便更好地理解闭包,这正是我学到的非常多。

#3


46  

...but what about the previous round parenteses surrounding all the function declaration?

…但是,在所有功能声明的周围,前一轮的parenteses又如何呢?

Specifically, it makes JavaScript interpret the 'function() {...}' construct as an inline anonymous function expression. If you omitted the brackets:

具体来说,它使JavaScript解释'function(){…}构造为内联匿名函数表达式。如果省略括号:

function() {
    alert('hello');
}();

You'd get a syntax error, because the JS parser would see the 'function' keyword and assume you're starting a function statement of the form:

你会得到一个语法错误,因为JS解析器会看到“function”关键字,并假设您正在启动表单的函数语句:

function doSomething() {
}

...and you can't have a function statement without a function name.

…没有函数名就不能有函数语句。

function expressions and function statements are two different constructs which are handled in very different ways. Unfortunately the syntax is almost identical, so it's not just confusing to the programmer, even the parser has difficulty telling which you mean!

函数表达式和函数语句是两种不同的结构,它们的处理方式非常不同。不幸的是,语法几乎是相同的,所以这不仅使程序员感到困惑,甚至解析器也难以说明您的意思!

#4


14  

Juts to follow up on what Andy Hume and others have said:

继续追踪安迪·休谟和其他人所说的话:

The '()' surrounding the anonymous function is the 'grouping operator' as defined in section 11.1.6 of the ECMA spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf.

围绕匿名函数的“()”是ECMA规范第11.1.6节中定义的“分组操作符”:http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf。

Taken verbatim from the docs:

从文件中逐字记录:

11.1.6 The Grouping Operator

11.1.6分组操作符

The production PrimaryExpression : ( Expression ) is evaluated as follows:

(表达式)的值计算如下:

  1. Return the result of evaluating Expression. This may be of type Reference.
  2. 返回表达式求值的结果。这可能是类型引用。

In this context the function is treated as an expression.

在此上下文中,函数被视为表达式。

#5


5  

A few considerations on the subject:

关于这个问题的一些考虑:

  • The parenthesis:

    括号:

    The browser (engine/parser) associates the keyword function with

    浏览器(引擎/解析器)将关键字函数与

    [optional name]([optional parameters]){...code...}
    

    So in an expression like function(){}() the last parenthesis makes no sense.

    因此,在函数(){}()的表达式中,最后一个括号没有意义。

    Now think at

    现在想在

    name=function(){} ; name() !?
    

Yes, the first pair of parenthesis force the anonymous function to turn into a variable (stored expression) and the second launches evaluation/execution, so ( function(){} )() makes sense.

是的,第一对括号强制匿名函数转换为变量(存储表达式),第二个括号启动计算/执行,因此(function(){})()是有意义的。

  • The utility: ?

    用途:?

    1. For executing some code on load and isolate the used variables from the rest of the page especially when name conflicts are possible;

      在加载时执行一些代码并将使用的变量与页面的其他部分隔离,特别是在可能出现名称冲突时;

    2. Replace eval("string") with

      取代eval(“字符串”)

      (new Function("string"))()

      (新功能(“字符串”))()

    3. Wrap long code for " =?: " operator like:

      为“=?”包装长代码。:“运营商:

      result = exp_to_test ? (function(){... long_code ...})() : (function(){...})();

      结果= exp_to_test ?(函数(){…long_code…})():(函数(){…})();

#6


3  

The first parentheses are for, if you will, order of operations. The 'result' of the set of parentheses surrounding the function definition is the function itself which, indeed, the second set of parentheses executes.

第一个括号表示操作的顺序。围绕函数定义的圆括号集合的“结果”是函数本身,实际上,第二组圆括号是执行的。

As to why it's useful, I'm not enough of a JavaScript wizard to have any idea. :P

至于它为什么有用,我对JavaScript向导还不了解。:P

#7


1  

See this question. The first set of parenthesis aren't necessary if you use a function name, but a nameless function requires this construct and the parenthesis serve for coders to realize that they've viewing a self-invoking function when browsing the code (see one blogger's best-practices recommendation).

看到这个问题。如果您使用函数名,那么第一个括号是不必要的,但是一个无名的函数需要这个构造,而圆括号则服务于编码器,以实现在浏览代码时查看自调用函数(参见一个blogger的最佳实践推荐)。