I've recently started maintaining someone else's JavaScript code. I'm fixing bugs, adding features and also trying to tidy up the code and make it more consistent.
我最近开始维护别人的JavaScript代码。我正在修复bug,添加特性,并试图整理代码,使代码更加一致。
The previous developer uses two ways of declaring functions and I can't work out if there is a reason behind it or not.
前面的开发人员使用了两种声明函数的方式,如果有原因,我就无法确定。
The two ways are:
两种方式是:
var functionOne = function() {
// Some code
};
function functionTwo() {
// Some code
}
What are the reasons for using these two different methods and what are the pros and cons of each? Is there anything that can be done with one method that can't be done with the other?
使用这两种不同方法的原因是什么?每种方法的优缺点是什么?有什么方法可以用一种方法不能用另一种方法完成?
31 个解决方案
#1
4338
The difference is that functionOne
is a function expression and so only defined when that line is reached, whereas functionTwo
is a function declaration and is defined as soon as its surrounding function or script is executed (due to hoisting).
不同之处在于,functionOne是一个函数表达式,因此只有在到达该行时才定义它,而functionTwo则是一个函数声明,它在其周围的函数或脚本被执行(由于挂起)时被定义。
For example, a function expression:
例如,函数表达式:
// TypeError: undefined is not a function
functionOne();
var functionOne = function() {
console.log("Hello!");
};
And, a function declaration:
,一个函数声明:
// Outputs: "Hello!"
functionTwo();
function functionTwo() {
console.log("Hello!");
}
This also means you can't conditionally define functions using function declarations:
这也意味着您不能使用函数声明有条件地定义函数:
if (test) {
// Error or misbehavior
function functionThree() { doSomething(); }
}
The above actually defines functionThree
irrespective of test
's value — unless use strict
is in effect, in which case it simply raises an error.
以上实际上定义了function3,而不考虑测试的值——除非使用严格的方法,在这种情况下,它只会产生一个错误。
#2
1753
First I want to correct Greg: function abc(){}
is scoped too — the name abc
is defined in the scope where this definition is encountered. Example:
首先,我想纠正格雷格:函数abc(){}也是作用域的——在遇到这个定义的范围内定义abc。例子:
function xyz(){
function abc(){};
// abc is defined here...
}
// ...but not here
Secondly, it is possible to combine both styles:
其次,可以将两种风格结合起来:
var xyz = function abc(){};
xyz
is going to be defined as usual, abc
is undefined in all browsers but Internet Explorer — do not rely on it being defined. But it will be defined inside its body:
xyz将被定义为通常的,abc在所有浏览器中都没有定义,但是Internet Explorer—不要依赖它被定义。但它会在体内被定义:
var xyz = function abc(){
// xyz is visible here
// abc is visible here
}
// xyz is visible here
// abc is undefined here
If you want to alias functions on all browsers, use this kind of declaration:
如果您想在所有浏览器上使用别名,请使用以下声明:
function abc(){};
var xyz = abc;
In this case, both xyz
and abc
are aliases of the same object:
在这种情况下,xyz和abc都是同一个对象的别名:
console.log(xyz === abc); // prints "true"
One compelling reason to use the combined style is the "name" attribute of function objects (not supported by Internet Explorer). Basically when you define a function like
使用组合样式的一个令人信服的原因是函数对象的“name”属性(不支持Internet Explorer)。当你定义一个函数的时候。
function abc(){};
console.log(abc.name); // prints "abc"
its name is automatically assigned. But when you define it like
它的名字是自动分配的。但是当你定义它的时候。
var abc = function(){};
console.log(abc.name); // prints ""
its name is empty — we created an anonymous function and assigned it to some variable.
它的名称是空的——我们创建了一个匿名函数,并将其分配给某个变量。
Another good reason to use the combined style is to use a short internal name to refer to itself, while providing a long non-conflicting name for external users:
使用组合样式的另一个很好的理由是使用一个简短的内部名称来引用它本身,同时为外部用户提供一个长而非冲突的名称:
// Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
// Let it call itself recursively:
shortcut(n - 1);
// ...
// Let it pass itself as a callback:
someFunction(shortcut);
// ...
}
In the example above we can do the same with an external name, but it'll be too unwieldy (and slower).
在上面的例子中,我们可以用一个外部名称来做同样的事情,但是它太笨拙(而且更慢)。
(Another way to refer to itself is to use arguments.callee
, which is still relatively long, and not supported in the strict mode.)
另一种方法是使用参数。callee,它仍然相对较长,在严格的模式下不支持。
Deep down, JavaScript treats both statements differently. This is a function declaration:
在深层,JavaScript对这两个语句都有不同的处理。这是一个函数声明:
function abc(){}
abc
here is defined everywhere in the current scope:
这里的abc是在当前范围内的任何地方定义的:
// We can call it here
abc(); // Works
// Yet, it is defined down there.
function abc(){}
// We can call it again
abc(); // Works
Also, it hoisted through a return
statement:
此外,它还通过一份退货声明提出:
// We can call it here
abc(); // Works
return;
function abc(){}
This is a function expression:
这是一个函数表达式:
var xyz = function(){};
xyz
here is defined from the point of assignment:
这里的xyz是由作业点定义的:
// We can't call it here
xyz(); // UNDEFINED!!!
// Now it is defined
xyz = function(){}
// We can call it here
xyz(); // works
Function declaration vs. function expression is the real reason why there is a difference demonstrated by Greg.
函数声明与函数表达式是格雷格演示的差异的真正原因。
Fun fact:
有趣的事实:
var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"
Personally, I prefer the "function expression" declaration because this way I can control the visibility. When I define the function like
就个人而言,我更喜欢“函数表达式”声明,因为这样我可以控制可见性。当我定义函数的时候。
var abc = function(){};
I know that I defined the function locally. When I define the function like
我知道我在本地定义了函数。当我定义函数的时候。
abc = function(){};
I know that I defined it globally providing that I didn't define abc
anywhere in the chain of scopes. This style of definition is resilient even when used inside eval()
. While the definition
我知道,我在全球范围内定义了它,因为我没有在范围内的任何地方定义abc。这种类型的定义即使在eval()中使用时也是有弹性的。而定义
function abc(){};
depends on the context and may leave you guessing where it is actually defined, especially in the case of eval()
— the answer is: It depends on the browser.
取决于上下文,可能会让您猜测它实际上是在哪里定义的,特别是在eval()的情况下——答案是:它取决于浏览器。
#3
514
Here's the rundown on the standard forms that create functions: (Originally written for another question, but adapted after being moved into the canonical question.)
以下是创建函数的标准表单的纲要(最初是为另一个问题编写的,但在被转移到规范问题之后改编)。
Terms:
术语:
- ES5: ECMAScript 5th edition, 2009
- ES5: ECMAScript第五版,2009。
- ES2015: ECMAScript 2015 (also known as "ES6")
- ES2015: ECMAScript 2015(也被称为ES6)
The quick list:
快速列表:
-
Function Declaration
函数声明
-
"Anonymous"
function
Expression (which despite the term, sometimes create functions with names)“匿名”函数表达式(尽管有术语,有时会创建名称函数)
-
Named
function
Expression命名函数表达式
-
Accessor Function Initializer (ES5+)
访问器函数初始化(ES5 +)
-
Arrow Function Expression (ES2015+) (which, like anonymous function expressions, don't involve an explicit name, and yet can create functions with names)
箭头函数表达式(ES2015+)(它与匿名函数表达式一样,不涉及显式名称,但可以创建具有名称的函数)
-
Method Declaration in Object Initializer (ES2015+)
对象初始化器中的方法声明(ES2015+)
-
Constructor and Method Declarations in
class
(ES2015+)类的构造函数和方法声明(ES2015+)
Function Declaration
The first form is a function declaration, which looks like this:
第一个表单是一个函数声明,它看起来是这样的:
function x() {
console.log('x');
}
A function declaration is a declaration; it's not a statement or expression. As such, you don't follow it with a ;
(although doing so is harmless).
函数声明是一个声明;它不是一个陈述或表达。因此,你不会跟随它;(尽管这样做是无害的)。
A function declaration is processed when execution enters the context in which it appears, before any step-by-step code is executed. The function it creates is given a proper name (x
in the example above), and that name is put in the scope in which the declaration appears.
当执行进入其出现的上下文时,将处理函数声明,在执行任何分步代码之前。它创建的函数有一个适当的名称(上面示例中的x),并且该名称放在声明出现的范围内。
Because it's processed before any step-by-step code in the same context, you can do things like this:
因为它是在同一上下文中任何一步一步的代码之前处理的,你可以这样做:
x(); // Works even though it's above the declaration
function x() {
console.log('x');
}
Until ES2015, the spec didn't cover what a JavaScript engine should do if you put a function declaration inside a control structure like try
, if
, switch
, while
, etc., like this:
直到2015年,规范没有涵盖JavaScript引擎应该做的事情,如果您在控件结构中放入一个函数声明,如try、if、switch、while等,就像这样:
if (someCondition) {
function foo() { // <===== HERE THERE
} // <===== BE DRAGONS
}
And since they're processed before step-by-step code is run, it's tricky to know what to do when they're in a control structure.
而且由于它们是在一步一步的代码运行之前处理的,所以当它们处于控制结构中时,要知道该怎么做是很困难的。
Although doing this wasn't specified until ES2015, it was an allowable extension to support function declarations in blocks. Unfortunately (and inevitably), different engines did different things.
尽管在ES2015之前没有指定这样做,但它是支持块中的函数声明的允许扩展。不幸的是(不可避免地),不同的引擎做了不同的事情。
As of ES2015, the specification says what to do. In fact, it gives three separate things to do:
截止到2015年,规范规定了该做什么。事实上,它有三件事要做:
- If in loose mode not on a web browser, the JavaScript engine is supposed to do one thing
- 如果在松散模式下,而不是在web浏览器上,JavaScript引擎应该做一件事。
- If in loose mode on a web browser, the JavaScript engine is supposed to do something else
- 如果在web浏览器上使用松散模式,则JavaScript引擎应该执行其他操作。
- If in strict mode (browser or not), the JavaScript engine is supposed to do yet another thing
- 如果在严格的模式下(浏览器或非浏览器),JavaScript引擎应该做另一件事。
The rules for the loose modes are tricky, but in strict mode, function declarations in blocks are easy: They're local to the block (they have block scope, which is also new in ES2015), and they're hoisted to the top of the block. So:
松散模式的规则很复杂,但是在严格的模式下,块的函数声明很简单:它们是块的本地(它们有块作用域,在ES2015中也是新的),它们被提升到块的顶部。所以:
"use strict";
if (someCondition) {
foo(); // Works just fine
function foo() {
}
}
console.log(typeof foo); // "undefined" (`foo` is not in scope here
// because it's not in the same block)
"Anonymous" function
Expression
The second common form is called an anonymous function expression:
第二种常见形式称为匿名函数表达式:
var y = function () {
console.log('y');
};
Like all expressions, it's evaluated when it's reached in the step-by-step execution of the code.
和所有表达式一样,它是在代码逐步执行时进行评估的。
In ES5, the function this creates has no name (it's anonymous). In ES2015, the function is assigned a name if possible by inferring it from context. In the example above, the name would be y
. Something similar is done when the function is the value of a property initializer. (For details on when this happens and the rules, search for SetFunctionName
in the the specification — it appears all over the place.)
在ES5中,这个创建的函数没有名称(它是匿名的)。在ES2015中,如果可能的话,通过从上下文推断出该函数的名称。在上面的示例中,名称为y。当函数是属性初始值设定项的值时,类似的操作就完成了。(关于何时发生和规则的详细信息,请在规范中搜索SetFunctionName,它会出现在所有地方。)
Named function
Expression
The third form is a named function expression ("NFE"):
第三种形式是一个命名函数表达式(“NFE”):
var z = function w() {
console.log('zw')
};
The function this creates has a proper name (w
in this case). Like all expressions, this is evaluated when it's reached in the step-by-step execution of the code. The name of the function is not added to the scope in which the expression appears; the name is in scope within the function itself:
这个函数创建的函数有一个专有名称(在本例中为w)。就像所有表达式一样,在代码的逐步执行过程中进行评估。函数的名称不添加到表达式出现的范围;名称在函数本身的范围内:
var z = function w() {
console.log(typeof w); // "function"
};
console.log(typeof w); // "undefined"
Note that NFEs have frequently been a source of bugs for JavaScript implementations. IE8 and earlier, for instance, handle NFEs completely incorrectly, creating two different functions at two different times. Early versions of Safari had issues as well. The good news is that current versions of browsers (IE9 and up, current Safari) don't have those issues any more. (But as of this writing, sadly, IE8 remains in widespread use, and so using NFEs with code for the web in general is still problematic.)
注意,NFEs经常是JavaScript实现的bug源。例如,IE8和更早的时候,完全错误地处理NFEs,在两个不同的时间创建两个不同的函数。Safari的早期版本也有问题。好消息是目前的浏览器版本(IE9和最新的Safari浏览器)已经不再有这些问题了。(但遗憾的是,在撰写本文时,IE8仍在广泛使用,所以使用NFEs编写web代码仍然是个问题。)
Accessor Function Initializer (ES5+)
Sometimes functions can sneak in largely unnoticed; that's the case with accessor functions. Here's an example:
有时,功能可以悄无声息地潜入;这就是accessor函数的情况。这里有一个例子:
var obj = {
value: 0,
get f() {
return this.value;
},
set f(v) {
this.value = v;
}
};
console.log(obj.f); // 0
console.log(typeof obj.f); // "number"
Note that when I used the function, I didn't use ()
! That's because it's an accessor function for a property. We get and set the property in the normal way, but behind the scenes, the function is called.
注意,当我使用这个函数时,我没有使用()!这是因为它是属性的访问函数。我们以正常的方式获取和设置属性,但是在幕后,函数被调用。
You can also create accessor functions with Object.defineProperty
, Object.defineProperties
, and the lesser-known second argument to Object.create
.
您还可以使用Object.defineProperty、Object.defineProperties和不太知名的第二个参数创建accessor函数。
Arrow Function Expression (ES2015+)
ES2015 brings us the arrow function. Here's one example:
ES2015给我们带来了箭头函数。这里有一个例子:
var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6
See that n => n * 2
thing hiding in the map()
call? That's a function.
看到在map()调用中隐藏的n => n * 2的东西吗?这是一个函数。
A couple of things about arrow functions:
关于箭头函数有几点
-
They don't have their own
this
. Instead, they close over thethis
of the context where they're defined. (They also close overarguments
and, where relevant,super
.) This means that thethis
within them is the same as thethis
where they're created, and cannot be changed.他们没有自己的这个。相反,它们会在定义它们的上下文中结束。(他们也会结束争论,并在相关的情况下超赞。)这意味着在它们内部的这个和它们创建的地方是一样的,并且不能被改变。
-
As you'll have noticed with the above, you don't use the keyword
function
; instead, you use=>
.正如您在上面所看到的,您不使用关键字函数;相反,您使用= >。
The n => n * 2
example above is one form of them. If you have multiple arguments to pass the function, you use parens:
上面的n => n * 2是其中一种形式。如果有多个参数传递函数,则使用parens:
var a = [1, 2, 3];
var b = a.map((n, i) => n * i);
console.log(b.join(", ")); // 0, 2, 6
(Remember that Array#map
passes the entry as the first argument, and the index as the second.)
(请记住,数组#map将条目作为第一个参数传递,而索引作为第二个参数。)
In both cases, the body of the function is just an expression; the function's return value will automatically be the result of that expression (you don't use an explicit return
).
在这两种情况下,函数的主体只是一个表达式;函数的返回值将自动成为该表达式的结果(您不使用显式返回)。
If you're doing more than just a single expression, use {}
and an explicit return
(if you need to return a value), as normal:
如果您正在做的不仅仅是一个表达式,使用{}和显式返回(如果您需要返回一个值),这是正常的:
var a = [
{first: "Joe", last: "Bloggs"},
{first: "Albert", last: "Bloggs"},
{first: "Mary", last: "Albright"}
];
a = a.sort((a, b) => {
var rv = a.last.localeCompare(b.last);
if (rv === 0) {
rv = a.first.localeCompare(b.first);
}
return rv;
});
console.log(JSON.stringify(a));
The version without { ... }
is called an arrow function with an expression body or concise body. (Also: A concise arrow function.) The one with { ... }
defining the body is an arrow function with a function body. (Also: A verbose arrow function.)
没有{…}被称为一个带有表达式体或简洁主体的箭头函数。(还有一个简洁的箭头函数。)有{…定义主体是一个带有函数体的箭头函数。(还有一个详细的箭头函数。)
Method Declaration in Object Initializer (ES2015+)
ES2015 allows a shorter form of declaring a property that references a function; it looks like this:
ES2015允许更短的形式声明引用函数的属性;它看起来像这样:
var o = {
foo() {
}
};
the equivalent in ES5 and earlier would be:
在ES5和更早时的等效项是:
var o = {
foo: function foo() {
}
};
Constructor and Method Declarations in class
(ES2015+)
ES2015 brings us class
syntax, including declared constructors and methods:
ES2015带来了类语法,包括声明的构造函数和方法:
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName() {
return this.firstName + " " + this.lastName;
}
}
There are two function declarations above: One for the constructor, which gets the name Person
, and one for getFullName
, which is a function assigned to Person.prototype
.
上面有两个函数声明:一个用于构造函数,一个用于获取名称,另一个用于getFullName,这是一个分配给Person.prototype的函数。
#4
125
Speaking about the global context, both, the var
statement and a FunctionDeclaration
at the end will create a non-deleteable property on the global object, but the value of both can be overwritten.
在谈到全局上下文时,两端的var语句和函数声明将在全局对象上创建一个不可删除的属性,但是两者的值都可以被覆盖。
The subtle difference between the two ways is that when the Variable Instantiation process runs (before the actual code execution) all identifiers declared with var
will be initialized with undefined
, and the ones used by the FunctionDeclaration
's will be available since that moment, for example:
这两种方法之间的细微差别在于,当变量实例化进程运行(在实际的代码执行之前)时,使用var声明的所有标识符都将被初始化,并没有定义,而FunctionDeclaration所使用的标识符将从那一时刻开始使用,例如:
alert(typeof foo); // 'function', it's already available
alert(typeof bar); // 'undefined'
function foo () {}
var bar = function () {};
alert(typeof bar); // 'function'
The assignment of the bar
FunctionExpression
takes place until runtime.
bar FunctionExpression的赋值在运行时发生。
A global property created by a FunctionDeclaration
can be overwritten without any problems just like a variable value, e.g.:
由FunctionDeclaration创建的全局属性可以被重写,而不需要像变量值一样的问题。
function test () {}
test = null;
Another obvious difference between your two examples is that the first function doesn't have a name, but the second has it, which can be really useful when debugging (i.e. inspecting a call stack).
两个示例之间的另一个明显区别是,第一个函数没有名称,但是第二个函数有它,这在调试(即检查调用堆栈)时非常有用。
About your edited first example (foo = function() { alert('hello!'); };
), it is an undeclared assignment, I would highly encourage you to always use the var
keyword.
关于您编辑的第一个示例(foo = function() {alert('hello!');),它是一个未声明的赋值,我强烈建议您始终使用var关键字。
With an assignment, without the var
statement, if the referenced identifier is not found in the scope chain, it will become a deleteable property of the global object.
有了赋值,没有var语句,如果在范围链中没有找到引用的标识符,它将成为全局对象的可删除属性。
Also, undeclared assignments throw a ReferenceError
on ECMAScript 5 under Strict Mode.
此外,未声明的作业在严格模式下对ECMAScript 5抛出一个参考错误。
A must read:
一个必须阅读:
- Named function expressions demystified
- 命名函数表达式的启发
Note: This answer has been merged from another question, in which the major doubt and misconception from the OP was that identifiers declared with a FunctionDeclaration
, couldn't be overwritten which is not the case.
注意:这个答案已经与另一个问题合并了,在这个问题中,OP的主要疑问和误解是使用FunctionDeclaration声明的标识符,不能被覆盖,但事实并非如此。
#5
105
The two code snippets you've posted there will, for almost all purposes, behave the same way.
您在那里发布的两个代码片段几乎都将以相同的方式运行。
However, the difference in behaviour is that with the first variant (var functionOne = function() {}
), that function can only be called after that point in the code.
然而,行为的不同之处在于,在第一个变量(var functionOne = function(){})中,该函数只能在代码中的那个点之后调用。
With the second variant (function functionTwo()
), the function is available to code that runs above where the function is declared.
对于第二个变体(函数function2()),函数可以在函数声明的地方运行。
This is because with the first variant, the function is assigned to the variable foo
at run time. In the second, the function is assigned to that identifier, foo
, at parse time.
这是因为在第一个变量中,函数在运行时被分配给变量foo。在第二种情况下,函数被分配给该标识符,foo,在解析时间。
More technical information
更多的技术信息
JavaScript has three ways of defining functions.
JavaScript有三种定义函数的方法。
- Your first snippet shows a function expression. This involves using the "function" operator to create a function - the result of that operator can be stored in any variable or object property. The function expression is powerful that way. The function expression is often called an "anonymous function", because it does not have to have a name,
- 您的第一个代码片段显示了一个函数表达式。这涉及使用“函数”操作符来创建一个函数——该操作符的结果可以存储在任何变量或对象属性中。函数表达式的功能非常强大。函数表达式通常被称为“匿名函数”,因为它不必有名称,
- Your second example is a function declaration. This uses the "function" statement to create a function. The function is made available at parse time and can be called anywhere in that scope. You can still store it in a variable or object property later.
- 第二个示例是函数声明。这使用“函数”语句来创建一个函数。该函数在解析时可用,可以在该范围内的任何地方调用。您仍然可以在稍后将其存储在一个变量或对象属性中。
- The third way of defining a function is the "Function()" constructor, which is not shown in your original post. It's not recommended to use this as it works the same way as
eval()
, which has its problems. - 定义函数的第三种方法是“function()”构造函数,它在原始的post中没有显示。不建议使用它,因为它的工作方式与eval()相同,这有它的问题。
#6
85
A better explanation to Greg's answer
对格雷格的回答有更好的解释。
functionTwo();
function functionTwo() {
}
Why no error? We were always taught that expressions are executed from top to bottom(??)
为什么没有错误?我们一直都知道表达式是从上到下执行的(??)
Because:
Function declarations and variable declarations are always moved (
hoisted
) invisibly to the top of their containing scope by the JavaScript interpreter. Function parameters and language-defined names are, obviously, already there. ben cherry函数声明和变量声明总是被JavaScript解释器移到其包含范围的顶部。显然,函数参数和语言定义的名称已经存在。本樱桃
This means that code like this:
这意味着这样的代码:
functionOne(); --------------- var functionOne;
| is actually | functionOne();
var functionOne = function(){ | interpreted |-->
}; | like | functionOne = function(){
--------------- };
Notice that the assignment portion of the declarations were not hoisted. Only the name is hoisted.
请注意,声明的赋值部分没有挂起。只有这个名字被吊起来了。
But in the case with function declarations, the entire function body will be hoisted as well:
但是在函数声明的情况下,整个函数体也将被提升:
functionTwo(); --------------- function functionTwo() {
| is actually | };
function functionTwo() { | interpreted |-->
} | like | functionTwo();
---------------
#7
80
Other commenters have already covered the semantic difference of the two variants above. I wanted to note a stylistic difference: Only the "assignment" variation can set a property of another object.
其他评论者已经涵盖了上述两种变体的语义差异。我想要注意一种风格上的差异:只有“赋值”变体可以设置另一个对象的属性。
I often build JavaScript modules with a pattern like this:
我经常使用这样的模式构建JavaScript模块:
(function(){
var exports = {};
function privateUtil() {
...
}
exports.publicUtil = function() {
...
};
return exports;
})();
With this pattern, your public functions will all use assignment, while your private functions use declaration.
有了这个模式,您的公共函数将全部使用赋值,而您的私有函数使用声明。
(Note also that assignment should require a semicolon after the statement, while declaration prohibits it.)
(注意,在声明之后,赋值应该要求分号,而声明则禁止。)
#8
66
An illustration of when to prefer the first method to the second one is when you need to avoid overriding a function's previous definitions.
当您需要避免重写函数以前的定义时,说明何时优先使用第一个方法。
With
与
if (condition){
function myfunction(){
// Some code
}
}
, this definition of myfunction
will override any previous definition, since it will be done at parse-time.
这个myfunction的定义将覆盖任何以前的定义,因为它将在parse-time中完成。
While
而
if (condition){
var myfunction = function (){
// Some code
}
}
does the correct job of defining myfunction
only when condition
is met.
只有在条件满足时才定义myfunction的正确工作。
#9
53
An important reason is to add one and only one variable as the "Root" of your namespace...
一个重要的原因是添加一个变量作为名称空间的“根”。
var MyNamespace = {}
MyNamespace.foo= function() {
}
or
或
var MyNamespace = {
foo: function() {
},
...
}
There are many techniques for namespacing. It's become more important with the plethora of JavaScript modules available.
有许多用于命名空间的技术。对于大量可用的JavaScript模块,它变得更加重要。
Also see How do I declare a namespace in JavaScript?
还可以看到如何在JavaScript中声明名称空间?
#10
45
Hoisting is the JavaScript interpreter’s action of moving all variable and function declarations to the top of the current scope.
提升是JavaScript解释器的动作,它将所有变量和函数声明移动到当前范围的顶部。
However, only the actual declarations are hoisted. by leaving assignments where they are.
但是,只有实际的声明被挂起。把任务交给他们。
- variable's/Function's declared inside the page are global can access anywhere in that page.
- 在页面中声明的变量的/函数是全局的,可以访问该页面中的任何位置。
- variable's/Functions declared inside the function are having local scope. means they are available/accessed inside the function body (scope), they are not available outside the function body.
- 函数内声明的变量/函数具有局部范围。表示它们在函数体(范围)内可用/访问,它们在函数体之外是不可用的。
变量
Javascript is called loosely typed language. Which means Javascript variables can hold value of any Data-Type. Javascript automatically takes care of changing the variable-type based on the value/literal provided during runtime.
Javascript被称为松散类型语言。这意味着Javascript变量可以保存任何数据类型的值。Javascript会自动地根据运行时提供的值/文字来改变变量类型。
global_Page = 10; var global_Page; « undefined
« Integer literal, Number Type. ------------------- global_Page = 10; « Number
global_Page = 'Yash'; | Interpreted | global_Page = 'Yash'; « String
« String literal, String Type. « AS « global_Page = true; « Boolean
var global_Page = true; | | global_Page = function (){ « function
« Boolean Type ------------------- var local_functionblock; « undefined
global_Page = function (){ local_functionblock = 777;« Number
var local_functionblock = 777; };
// Assigning function as a data.
};
Function
函数
function Identifier_opt ( FormalParameterList_opt ) {
FunctionBody | sequence of statements
« return; Default undefined
« return 'some data';
}
- functions declared inside the page are hoisted to top of the page having global access.
- 页面内声明的函数将被提升到具有全局访问权的页面顶部。
- functions declared inside the function-block are hoisted to top of the block.
- 函数块内部声明的函数被提升到块的顶部。
-
Default return value of function is 'undefined', Variable declaration default value also 'undefined'
函数的默认返回值是“未定义的”,变量声明默认值也“未定义”
Scope with respect to function-block global. Scope with respect to page undefined | not available.
Function Declaration
函数声明
function globalAccess() { function globalAccess() {
} ------------------- }
globalAccess(); | | function globalAccess() { « Re-Defined / overridden.
localAccess(); « Hoisted As « function localAccess() {
function globalAccess() { | | }
localAccess(); ------------------- localAccess(); « function accessed with in globalAccess() only.
function localAccess() { }
} globalAccess();
} localAccess(); « ReferenceError as the function is not defined
Function Expression
函数表达式
10; « literal
(10); « Expression (10).toString() -> '10'
var a;
a = 10; « Expression var a.toString() -> '10'
(function invoke() { « Expression Function
console.log('Self Invoking'); (function () {
}); }) () -> 'Self Invoking'
var f;
f = function (){ « Expression var Function
console.log('var Function'); f () -> 'var Function'
};
Function assigned to variable Example:
分配给变量示例的函数:
(function selfExecuting(){
console.log('IIFE - Immediately-Invoked Function Expression');
}());
var anonymous = function (){
console.log('anonymous function Expression');
};
var namedExpression = function for_InternalUSE(fact){
if(fact === 1){
return 1;
}
var localExpression = function(){
console.log('Local to the parent Function Scope');
};
globalExpression = function(){
console.log('creates a new global variable, then assigned this function.');
};
//return; //undefined.
return fact * for_InternalUSE( fact - 1);
};
namedExpression();
globalExpression();
javascript interpreted as
javascript解释为
var anonymous;
var namedExpression;
var globalExpression;
anonymous = function (){
console.log('anonymous function Expression');
};
namedExpression = function for_InternalUSE(fact){
var localExpression;
if(fact === 1){
return 1;
}
localExpression = function(){
console.log('Local to the parent Function Scope');
};
globalExpression = function(){
console.log('creates a new global variable, then assigned this function.');
};
return fact * for_InternalUSE( fact - 1); // DEFAULT UNDEFINED.
};
namedExpression(10);
globalExpression();
You can check function declaration, expression test over different browser's using jsperf Test Runner
您可以使用jsperf测试运行器检查函数声明、表达式测试。
ES5 Constructor Function Classes: Function objects created using Function.prototype.bind
ES5构造函数类:使用函数创建的函数对象。
JavaScript treats functions as first-class objects, so being an object, you can assign properties to a function.
JavaScript将函数视为一级对象,因此作为对象,可以将属性赋给函数。
function Shape(id) { // Function Declaration
this.id = id;
};
// Adding a prototyped method to a function.
Shape.prototype.getID = function () {
return this.id;
};
Shape.prototype.setID = function ( id ) {
this.id = id;
};
var expFn = Shape; // Function Expression
var funObj = new Shape( ); // Function Object
funObj.hasOwnProperty('prototype'); // false
funObj.setID( 10 );
console.log( funObj.getID() ); // 10
ES6 introduced Arrow function: An arrow function expression has a shorter syntax, they are best suited for non-method functions, and they cannot be used as constructors.
ES6引入了箭头函数:一个箭头函数表达式的语法较短,它们最适合于非方法函数,它们不能作为构造函数使用。
ArrowFunction : ArrowParameters => ConciseBody
.ArrowFunction: ArrowParameters => ConciseBody。
const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; }; console.log( fn(2) ); // Even console.log( fn(3) ); // Odd
#11
32
I'm adding my own answer just because everyone else has covered the hoisting part thoroughly.
我只是在加上我自己的答案,因为其他所有人都把吊装部分完全盖住了。
I've wondered about which way is better for a long while now, and thanks to http://jsperf.com now I know :)
我一直在想,这条路在很长一段时间内会变得更好,多亏了http://jsperf.com,现在我知道了:
Function declarations are faster, and that's what really matters in web dev right? ;)
函数声明更快,这才是web开发中真正重要的东西?,)
#12
29
A function declaration and a function expression assigned to a variable behave the same once the binding is established.
当绑定建立时,赋值给一个变量的函数声明和函数表达式。
There is a difference however at how and when the function object is actually associated with its variable. This difference is due to the mechanism called variable hoisting in JavaScript.
然而,当函数对象与它的变量相关联时,有一个不同之处。这种差异是由于在JavaScript中被称为变量提升的机制。
Basically, all function declarations and variable declarations are hoisted to the top of the function in which the declaration occurs (this is why we say that JavaScript has function scope).
基本上,所有函数声明和变量声明都被提升到声明发生的函数的顶部(这就是为什么我们说JavaScript有函数作用域)。
-
When a function declaration is hoisted, the function body "follows" so when the function body is evaluated, the variable will immediately be bound to a function object.
当函数声明被挂起时,函数体“跟随”,当函数体被求值时,变量将立即被绑定到一个函数对象。
-
When a variable declaration is hoisted, the initialization does not follow, but is "left behind". The variable is initialized to
undefined
at the start of the function body, and will be assigned a value at its original location in the code. (Actually, it will be assigned a value at every location where a declaration of a variable with the same name occurs.)当一个变量声明被升起时,初始化不会跟随,而是被“留下”。变量在函数体开始时初始化为未定义,并将在代码的原始位置赋值。(实际上,它将在每个位置上分配一个值,在该位置上出现一个同名变量的声明。)
The order of hoisting is also important: function declarations take precedence over variable declarations with the same name, and the last function declaration takes precedence over previous function declarations with the same name.
提升的顺序也很重要:函数声明优先于具有相同名称的变量声明,而最后一个函数声明优先于具有相同名称的前一个函数声明。
Some examples...
一些例子…
var foo = 1;
function bar() {
if (!foo) {
var foo = 10 }
return foo; }
bar() // 10
Variable foo
is hoisted to the top of the function, initialized to undefined
, so that !foo
is true
, so foo
is assigned 10
. The foo
outside of bar
's scope plays no role and is untouched.
变量foo被提升到函数的顶部,初始化为未定义的,因此,foo是true,所以foo被赋值为10。在bar的范围之外的foo没有作用,没有被修改。
function f() {
return a;
function a() {return 1};
var a = 4;
function a() {return 2}}
f()() // 2
function f() {
return a;
var a = 4;
function a() {return 1};
function a() {return 2}}
f()() // 2
Function declarations take precedence over variable declarations, and the last function declaration "sticks".
函数声明优先于变量声明,最后一个函数声明“棒”。
function f() {
var a = 4;
function a() {return 1};
function a() {return 2};
return a; }
f() // 4
In this example a
is initialized with the function object resulting from evaluating the second function declaration, and then is assigned 4
.
在这个示例中,使用函数对象初始化了一个函数,结果是对第二个函数声明进行了评估,然后将其赋值为4。
var a = 1;
function b() {
a = 10;
return;
function a() {}}
b();
a // 1
Here the function declaration is hoisted first, declaring and initializing variable a
. Next, this variable is assigned 10
. In other words: the assignment does not assign to outer variable a
.
这里首先提升函数声明,声明和初始化变量a。接下来,这个变量被赋值为10。换句话说:赋值不能赋给外部变量a。
#13
26
The first example is a function declaration:
第一个示例是函数声明:
function abc(){}
The second example is a function expression:
第二个例子是函数表达式:
var abc = function() {};
The main difference is how they are hoisted (lifted and declared). In the first example, the whole function declaration is hoisted. In the second example only the var 'abc' is hoisted, its value (the function) will be undefined, and the function itself remains at the position that it is declared.
主要的区别是它们是如何被提升的(举起和声明)。在第一个示例中,将挂起整个函数声明。在第二个示例中,只有var 'abc'被挂起,它的值(函数)将没有定义,函数本身保留在声明的位置上。
To put it simply:
简而言之:
//this will work
abc(param);
function abc(){}
//this would fail
abc(param);
var abc = function() {}
To study more about this topic I strongly recommend you this link
为了进一步研究这个话题,我强烈推荐你这个链接。
#14
25
In terms of code maintenance cost, named functions are more preferable:
就代码维护成本而言,命名函数更可取:
- Independent from the place where they are declared (but still limited by scope).
- 独立于被声明的地方(但仍受范围限制)。
- More resistant to mistakes like conditional initialization (you are still able to override if wanted to).
- 更能抵抗像条件初始化这样的错误(如果需要,您仍然可以重写)。
- The code becomes more readable by allocating local functions separately of scope functionality. Usually in the scope the functionality goes first, followed by declarations of local functions.
- 通过将局部函数单独分配到作用域功能,代码变得更加可读。通常在功能的范围内,然后是局部函数的声明。
- In a debugger you will clearly see the function name on the call stack instead of an "anonymous/evaluated" function.
- 在调试器中,您将清楚地看到调用堆栈上的函数名,而不是“匿名/评估”函数。
I suspect more PROS for named functions are follow. And what is listed as an advantage of named functions is a disadvantage for anonymous ones.
我怀疑有更多关于命名函数的好处。命名函数的优点是匿名函数的缺点。
Historically, anonymous functions appeared from the inability of JavaScript as a language to list members with named functions:
从历史上看,匿名函数出现的原因是JavaScript无法作为一种语言来列出具有命名功能的成员:
{
member:function() { /* How do I make "this.member" a named function? */
}
}
#15
22
I use the variable approach in my code for a very specific reason, the theory of which has been covered in an abstract way above, but an example might help some people like me, with limited JavaScript expertise.
我在代码中使用了变量方法,这是一个非常具体的原因,它的理论已经以一种抽象的方式覆盖了,但是一个例子可能会帮助一些像我这样的人,使用有限的JavaScript技术。
I have code that I need to run with 160 independently-designed brandings. Most of the code is in shared files, but branding-specific stuff is in a separate file, one for each branding.
我有代码,我需要运行160个独立设计的品牌。大多数代码都在共享文件中,但是特定于品牌的东西在一个单独的文件中,一个用于每个品牌。
Some brandings require specific functions, and some do not. Sometimes I have to add new functions to do new branding-specific things. I am happy to change the shared coded, but I don't want to have to change all 160 sets of branding files.
有些品牌需要特定的功能,有些则不需要。有时候,我需要添加一些新的功能来做一些新的特定品牌的事情。我很乐意更改共享代码,但我不想更改所有160套品牌文件。
By using the variable syntax, I can declare the variable (a function pointer essentially) in the shared code and either assign a trivial stub function, or set to null.
通过使用变量语法,我可以在共享代码中声明变量(本质上是一个函数指针),并分配一个微不足道的存根函数,或者设置为null。
The one or two brandings that need a specific implementation of the function can then define their version of the function and assign this to the variable if they want, and the rest do nothing. I can test for a null function before I execute it in the shared code.
需要特定实现功能的一个或两个brandings可以定义函数的版本,并将其分配给变量,其余的则什么都不做。在执行共享代码之前,我可以测试一个空函数。
From people's comments above, I gather it may be possible to redefine a static function too, but I think the variable solution is nice and clear.
从上面的人的评论中,我也可以重新定义一个静态函数,但是我认为这个变量的解决方案是很清晰的。
#16
19
In computer science terms, we talk about anonymous functions and named functions. I think the most important difference is that an anonymous function is not bound to an name, hence the name anonymous function. In JavaScript it is a first class object dynamically declared at runtime.
在计算机科学术语中,我们讨论匿名函数和命名函数。我认为最重要的区别是匿名函数不受名称的约束,因此命名为匿名函数。在JavaScript中,它是在运行时动态声明的第一个类对象。
For more information on anonymous functions and lambda calculus, Wikipedia is a good start (http://en.wikipedia.org/wiki/Anonymous_function).
关于匿名函数和lambda微积分的更多信息,*是一个很好的开始。
#17
19
Greg's Answer is good enough, but I still would like to add something to it that I learned just now watching Douglas Crockford's videos.
格雷格的回答已经够好了,但我还是想给它添加一些东西,我刚刚才了解到道格拉斯·克罗克福德(Douglas Crockford)的视频。
Function expression:
函数表达式:
var foo = function foo() {};
Function statement:
函数声明:
function foo() {};
The function statement is just a shorthand for var
statement with a function
value.
函数语句只是具有函数值的var语句的简写。
So
所以
function foo() {};
expands to
扩大到
var foo = function foo() {};
Which expands further to:
进一步扩大:
var foo = undefined;
foo = function foo() {};
And they are both hoisted to the top of the code.
它们都被提升到了代码的顶端。
#18
16
@EugeneLazutkin gives an example where he names an assigned function to be able to use shortcut()
as an internal reference to itself. John Resig gives another example - copying a recursive function assigned to another object in his Learning Advanced Javascript tutorial. While assigning functions to properties isn't strictly the question here, I recommend actively trying the tutorial out - run the code by clicking the button in the upper right corner, and double click the code to edit to your liking.
@EugeneLazutkin给出了一个例子,他将一个指定的函数命名为可以使用快捷方式()作为内部引用。John Resig给出了另一个例子——在他学习的高级Javascript教程中,复制一个递归函数给另一个对象。虽然在这里不严格地将函数分配给属性,但我建议您积极地尝试一下教程——通过单击右上角的按钮来运行代码,双击代码以编辑您喜欢的代码。
Examples from the tutorial: recursive calls in yell()
:
本教程中的示例:yell()中的递归调用:
Tests fail when the original ninja object is removed. (page 13)
当原始的忍者对象被移除时,测试失败。(13页)
var ninja = {
yell: function(n){
return n > 0 ? ninja.yell(n-1) + "a" : "hiy";
}
};
assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." );
var samurai = { yell: ninja.yell };
var ninja = null;
try {
samurai.yell(4);
} catch(e){
assert( false, "Uh, this isn't good! Where'd ninja.yell go?" );
}
If you name the function that will be called recursively, the tests will pass. (page 14)
如果您命名将被递归调用的函数,则测试将通过。(14页)
var ninja = {
yell: function yell(n){
return n > 0 ? yell(n-1) + "a" : "hiy";
}
};
assert( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" );
var samurai = { yell: ninja.yell };
var ninja = {};
assert( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." );
#19
13
Another difference that is not mentioned in the other answers is that if you use the anonymous function
另一个不同之处是如果你使用匿名函数。
var functionOne = function() {
// Some code
};
and use that as a constructor as in
并将其用作构造函数。
var one = new functionOne();
then one.constructor.name
will not be defined. Function.name
is non-standard but is supported by Firefox, Chrome, other Webkit-derived browsers and IE 9+.
然后one.structor.name将不被定义。名称是不标准的,但由Firefox、Chrome、其他webkit派生的浏览器和ie9 +支持。
With
与
function functionTwo() {
// Some code
}
two = new functionTwo();
it is possible to retrieve the name of the constructor as a string with two.constructor.name
.
可以将构造函数的名称检索为带有two.constructor.name的字符串。
#20
13
If you would use those functions to create objects, you would get:
如果你使用这些函数来创建对象,你会得到:
var objectOne = new functionOne();
console.log(objectOne.__proto__); // prints "Object {}" because constructor is an anonymous function
var objectTwo = new functionTwo();
console.log(objectTwo.__proto__); // prints "functionTwo {}" because constructor is a named function
#21
13
I'm listing out the differences below:
我列出了下面的不同之处:
-
A function declaration can be placed anywhere in the code. Even if it is invoked before the definition appears in code, it gets executed as function declaration is committed to memory or in a way it is hoisted up, before any other code in the page starts execution.
函数声明可以放在代码的任何位置。即使在定义出现在代码中之前被调用,它也会被执行为函数声明,它会被提交到内存中,或者在页面中任何其他代码开始执行之前被提升。
Take a look at the function below:
看一下下面的函数:
function outerFunction() { function foo() { return 1; } return foo(); function foo() { return 2; } } alert(outerFunction()); // Displays 2
This is because, during execution, it looks like:-
这是因为在执行过程中,它看起来是这样的:-。
function foo() { // The first function declaration is moved to top return 1; } function foo() { // The second function declaration is moved to top return 2; } function outerFunction() { return foo(); } alert(outerFunction()); //So executing from top to bottom, //the last foo() returns 2 which gets displayed
A function expression, if not defined before calling it, will result in an error. Also, here the function definition itself is not moved to the top or committed to memory like in the function declarations. But the variable to which we assign the function gets hoisted up and undefined gets assigned to it.
函数表达式(如果在调用之前没有定义)将导致错误。同样,在这里,函数定义本身并没有移动到顶部,也不像在函数声明中那样提交到内存。但是我们分配函数的变量被提升了,而未定义的变量被赋值给它。
Same function using function expressions:
同样的函数使用函数表达式:
function outerFunction() { var foo = function() { return 1; } return foo(); var foo = function() { return 2; } } alert(outerFunction()); // Displays 1
This is because during execution, it looks like:
这是因为在执行过程中,它看起来是这样的:
function outerFunction() { var foo = undefined; var foo = undefined; foo = function() { return 1; }; return foo (); foo = function() { // This function expression is not reachable return 2; }; } alert(outerFunction()); // Displays 1
-
It is not safe to write function declarations in non-function blocks like if because they won't be accessible.
在非功能块中编写函数声明是不安全的,因为它们无法访问。
if (test) { function x() { doSomething(); } }
-
Named function expression like the one below, may not work in Internet Explorer browsers prior to version 9.
命名函数表达式如下所示,在版本9之前可能无法在Internet Explorer浏览器中工作。
var today = function today() {return new Date()}
#22
12
The first one (function doSomething(x)) should be part of an object notation.
第一个(函数doSomething(x))应该是对象表示法的一部分。
The second one (var doSomething = function(x){ alert(x);}
) is simply creating an anonymous function and assigning it to a variable, doSomething
. So doSomething() will call the function.
第二个(var doSomething = function(x){alert(x);})只是创建一个匿名函数,并将其分配给一个变量doSomething。doSomething()会调用函数。
You may want to know what a function declaration and function expression is.
您可能想知道函数声明和函数表达式是什么。
A function declaration defines a named function variable without requiring variable assignment. Function declarations occur as standalone constructs and cannot be nested within non-function blocks.
函数声明定义了一个命名函数变量,而不需要变量赋值。函数声明作为独立的结构出现,不能嵌套在非功能块中。
function foo() {
return 3;
}
ECMA 5 (13.0) defines the syntax as
function Identifier ( FormalParameterListopt ) { FunctionBody }ECMA 5(13.0)将语法定义为函数标识符(FormalParameterListopt) {FunctionBody}
In above condition the function name is visible within its scope and the scope of its parent (otherwise it would be unreachable).
在上述条件下,函数名在其作用域及其父对象的范围内可见(否则将不可访问)。
And in a function expression
在函数表达式中。
A function expression defines a function as a part of a larger expression syntax (typically a variable assignment ). Functions defined via functions expressions can be named or anonymous. Function expressions should not start with “function”.
函数表达式将函数定义为更大的表达式语法的一部分(通常是变量赋值)。通过函数表达式定义的函数可以命名或匿名。函数表达式不应该以“函数”开头。
// Anonymous function expression
var a = function() {
return 3;
}
// Named function expression
var a = function foo() {
return 3;
}
// Self-invoking function expression
(function foo() {
alert("hello!");
})();
ECMA 5 (13.0) defines the syntax as
function Identifieropt ( FormalParameterListopt ) { FunctionBody }ECMA 5(13.0)将语法定义为函数标识符(FormalParameterListopt) {FunctionBody}
#23
10
In light of the "named functions show up in stack traces" argument, modern JavaScript engines are actually quite capable of representing anonymous functions.
根据“在堆栈跟踪中显示的命名函数”的观点,现代JavaScript引擎实际上很有能力表示匿名函数。
As of this writing, V8, SpiderMonkey, Chakra and Nitro always refer to named functions by their names. They almost always refer to an anonymous function by its identifier if it has one.
在这篇文章中,V8、SpiderMonkey、Chakra和Nitro总是以它们的名字命名函数。如果有一个匿名函数,它们几乎总是引用它的标识符。
SpiderMonkey can figure out the name of an anonymous function returned from another function. The rest can't.
SpiderMonkey可以计算出从另一个函数返回的匿名函数的名称。剩下的不能。
If you really, really wanted your iterator and success callbacks to show up in the trace, you could name those too...
如果你真的想要你的迭代器和成功回调显示在跟踪中,你也可以命名它们。
[].forEach(function iterator() {});
But for the most part it's not worth stressing over.
但在很大程度上,这并不值得强调。
Harness (Fiddle)
'use strict';
var a = function () {
throw new Error();
},
b = function b() {
throw new Error();
},
c = function d() {
throw new Error();
},
e = {
f: a,
g: b,
h: c,
i: function () {
throw new Error();
},
j: function j() {
throw new Error();
},
k: function l() {
throw new Error();
}
},
m = (function () {
return function () {
throw new Error();
};
}()),
n = (function () {
return function n() {
throw new Error();
};
}()),
o = (function () {
return function p() {
throw new Error();
};
}());
console.log([a, b, c].concat(Object.keys(e).reduce(function (values, key) {
return values.concat(e[key]);
}, [])).concat([m, n, o]).reduce(function (logs, func) {
try {
func();
} catch (error) {
return logs.concat('func.name: ' + func.name + '\n' +
'Trace:\n' +
error.stack);
// Need to manually log the error object in Nitro.
}
}, []).join('\n\n'));
V8
func.name:
Trace:
Error
at a (http://localhost:8000/test.js:4:11)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: b
Trace:
Error
at b (http://localhost:8000/test.js:7:15)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: d
Trace:
Error
at d (http://localhost:8000/test.js:10:15)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name:
Trace:
Error
at a (http://localhost:8000/test.js:4:11)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: b
Trace:
Error
at b (http://localhost:8000/test.js:7:15)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: d
Trace:
Error
at d (http://localhost:8000/test.js:10:15)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name:
Trace:
Error
at e.i (http://localhost:8000/test.js:17:19)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: j
Trace:
Error
at j (http://localhost:8000/test.js:20:19)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: l
Trace:
Error
at l (http://localhost:8000/test.js:23:19)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name:
Trace:
Error
at http://localhost:8000/test.js:28:19
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: n
Trace:
Error
at n (http://localhost:8000/test.js:33:19)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: p
Trace:
Error
at p (http://localhost:8000/test.js:38:19)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27 test.js:42
SpiderMonkey
func.name:
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name:
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name:
Trace:
e.i@http://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: j
Trace:
j@http://localhost:8000/test.js:20:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: l
Trace:
l@http://localhost:8000/test.js:23:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name:
Trace:
m</<@http://localhost:8000/test.js:28:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: n
Trace:
n@http://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: p
Trace:
p@http://localhost:8000/test.js:38:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
Chakra
func.name: undefined
Trace:
Error
at a (http://localhost:8000/test.js:4:5)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at b (http://localhost:8000/test.js:7:9)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at d (http://localhost:8000/test.js:10:9)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at a (http://localhost:8000/test.js:4:5)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at b (http://localhost:8000/test.js:7:9)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at d (http://localhost:8000/test.js:10:9)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at e.i (http://localhost:8000/test.js:17:13)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at j (http://localhost:8000/test.js:20:13)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at l (http://localhost:8000/test.js:23:13)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at Anonymous function (http://localhost:8000/test.js:28:13)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at n (http://localhost:8000/test.js:33:13)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at p (http://localhost:8000/test.js:38:13)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
Nitro
func.name:
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name:
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name:
Trace:
i@http://localhost:8000/test.js:17:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: j
Trace:
j@http://localhost:8000/test.js:20:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: l
Trace:
l@http://localhost:8000/test.js:23:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name:
Trace:
http://localhost:8000/test.js:28:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: n
Trace:
n@http://localhost:8000/test.js:33:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: p
Trace:
p@http://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
#24
9
In JavaScript there are two ways to create functions:
在JavaScript中有两种创建函数的方法:
-
Function declaration:
函数声明:
function fn(){ console.log("Hello"); } fn();
This is very basic, self-explanatory, used in many languages and standard across C family of languages. We declared a function defined it and executed it by calling it.
这是非常基本的,不言自明的,用在许多语言和标准的C族语言中。我们声明一个函数定义它并通过调用它来执行它。
What you should be knowing is that functions are actually objects in JavaScript; internally we have created an object for above function and given it a name called fn or the reference to the object is stored in fn. Functions are objects in JavaScript; an instance of function is actually an object instance.
你应该知道函数实际上是JavaScript中的对象;在内部,我们为上面的函数创建了一个对象,并给它一个名为fn的名称,或者该对象的引用存储在fn中。函数是JavaScript中的对象;函数的实例实际上是一个对象实例。
-
Function expression:
函数表达式:
var fn=function(){ console.log("Hello"); } fn();
JavaScript has first-class functions, that is, create a function and assign it to a variable just like you create a string or number and assign it to a variable. Here, the fn variable is assigned to a function. The reason for this concept is functions are objects in JavaScript; fn is pointing to the object instance of the above function. We have initialized a function and assigned it to a variable. It's not executing the function and assigning the result.
JavaScript有一流的函数,即创建一个函数,并将其赋值给一个变量,就像你创建一个字符串或数字一样,并将其赋值给一个变量。这里,fn变量被分配给一个函数。这个概念的原因是函数是JavaScript中的对象;fn指向上述函数的对象实例。我们已经初始化了一个函数并将其赋值给一个变量。它没有执行函数并分配结果。
Reference: JavaScript function declaration syntax: var fn = function() {} vs function fn() {}
引用:JavaScript函数声明语法:var fn = function() {} vs函数fn() {}
#25
7
Both are different ways of defining a function. The difference is how the browser interprets and loads them into an execution context.
两者都是定义函数的不同方法。区别在于浏览器如何解释并将它们加载到执行上下文。
The first case is of function expressions which loads only when the interpreter reaches that line of code. So if you do it like the following, you will get an error that the functionOne is not a function.
第一个例子是函数表达式,只有当解释器到达这一行代码时才加载。如果你像下面这样做,你会得到一个错误,函数一不是函数。
functionOne();
var functionOne = function() {
// Some code
};
The reason is that on the first line no value is assigned to functionOne, and hence it is undefined. We are trying to call it as a function, and hence we are getting an error.
原因是在第一行中没有赋值给functionOne,因此它是未定义的。我们试着把它叫做函数,因此我们得到了一个错误。
On the second line we are assigning the reference of an anonymous function to functionOne.
在第二行中,我们将一个匿名函数的引用分配给functionOne。
The second case is of function declarations that loads before any code is executed. So if you do like the following you won't get any error as the declaration loads before code execution.
第二个例子是在执行任何代码之前加载的函数声明。因此,如果您这样做,您将不会在代码执行之前得到任何错误。
functionOne();
function functionOne() {
// Some code
}
#26
6
They are pretty similar with some small differences, first one is a variable which assigned to an anonymous function (Function Declaration) and second one is the normal way to create a function in JavaScript(Anonymous function Declaration), both has usage, cons and pros:
它们与一些细微的差别非常相似,第一个是分配给一个匿名函数(函数声明)的变量,第二个是在JavaScript中创建函数的正常方法(匿名函数声明),两者都有使用、反对和优点:
1. Function Expression
1。函数表达式
var functionOne = function() {
// Some code
};
A Function Expression defines a function as a part of a larger expression syntax (typically a variable assignment ). Functions defined via Functions Expressions can be named or anonymous. Function Expressions must not start with “function” (hence the parentheses around the self invoking example below).
函数表达式将函数定义为更大的表达式语法的一部分(通常是变量赋值)。通过函数表达式定义的函数可以命名或匿名。函数表达式不能以“函数”开头(因此,在下面的self调用示例中有一个圆括号)。
Assign a variable to a function, means no Hoisting, as we know functions in JavaScript can Hoist, means they can be called before they get declared, while variables need to be declared before getting access to them, so means in this case we can not access the function before where it's declared, also it could be a way that you write your functions, for the functions which return another function, this kind of declaration could make sense, also in ECMA6 & above you can assign this to an arrow function which can be used to call anonymous functions, also this way of declaring is a better way to create Constructor functions in JavaScript.
给变量分配一个函数,意味着没有提升,因为我们知道在JavaScript函数可以提升,意味着他们可以被称为之前宣布,而变量需要声明访问之前,在这种情况下,所以就意味着我们不能访问函数的声明之前,也可以是一种编写函数,函数返回另一个函数,这样的声明可以有意义,也在ECMA6 &上面你可以指定这个箭函数可用于调用匿名函数,这样的声明是一个更好的方法来创建JavaScript构造器函数。
2. Function Declaration
2。函数声明
function functionTwo() {
// Some code
}
A Function Declaration defines a named function variable without requiring variable assignment. Function Declarations occur as standalone constructs and cannot be nested within non-function blocks. It’s helpful to think of them as siblings of Variable Declarations. Just as Variable Declarations must start with “var”, Function Declarations must begin with “function”.
函数声明定义了一个命名函数变量,而不需要变量赋值。函数声明作为独立的结构出现,不能嵌套在非功能块中。把它们看作变量声明的兄弟姐妹是有帮助的。正如变量声明必须以“var”开头,函数声明必须以“函数”开始。
This is the normal way of calling a function in JavaScript, this function can be called before you even declare it as in JavaScript all functions get Hoisted, but if you have 'use strict' this won't Hoist as expected, it's a good way to call all normal functions which are not big in lines and neither are a constructor function.
这是正常的方式调用JavaScript函数,这个函数可以调用在你即使是在JavaScript函数声明它升起,但是如果你有使用严格的这不会提升正如预期的那样,这是一个好方法调用所有正常的功能并不大也行是一个构造函数。
Also, if you need more info about how hoisting works in JavaScript, visit the link below:
另外,如果您需要更多关于如何使用JavaScript进行提升的信息,请访问下面的链接:
https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
#27
6
About performance:
性能:
New versions of V8
introduced several under-the-hood optimizations and so did SpiderMonkey
.
V8的新版本引入了几个底层优化,SpiderMonkey也是如此。
There is almost no difference now between expression and declaration.
Function expression appears to be faster now.
表达式和声明之间几乎没有区别。函数表达式现在看起来更快了。
Chrome 62.0.3202
FireFox 55
Chrome金丝雀63.0.3225
Anonymous
function expressions appear to have better performance againstNamed
function expression.匿名函数表达式在命名函数表达式上似乎有更好的性能。
火狐浏览器Chrome金丝雀铬
#28
3
This is just two possible ways of declaring functions, and in the second way, you can use the function before declaration.
这仅仅是声明函数的两种方法,在第二种方法中,您可以在声明之前使用函数。
#29
3
new Function()
can be used to pass the function's body in a string. And hence this can be used to create dynamic functions. Also passing the script without executing the script.
可以使用new Function()将函数的主体传递给字符串。因此,这可以用来创建动态函数。还可以在不执行脚本的情况下传递脚本。
var func = new Function("x", "y", "return x*y;");
function secondFunction(){
var result;
result = func(10,20);
console.log ( result );
}
secondFunction()
#30
0
I prefer defining function as variable:
我喜欢将函数定义为变量:
let first = function(x){
return x[0];
}
Instead of:
而不是:
function first(){
....
}
Because i can use expressions and decorators when defining the function. For example:
因为我可以在定义函数时使用表达式和修饰符。例如:
let safe = function(f){
try {f()...}
}
let last = safe(function(x){return x[0]}).
Also with ES6 its much shorter:
也有ES6更短:
let last = x => x[0]
...........
function last(x){
return x[0];
}
......
let last = safe(x => x[0]);
#1
4338
The difference is that functionOne
is a function expression and so only defined when that line is reached, whereas functionTwo
is a function declaration and is defined as soon as its surrounding function or script is executed (due to hoisting).
不同之处在于,functionOne是一个函数表达式,因此只有在到达该行时才定义它,而functionTwo则是一个函数声明,它在其周围的函数或脚本被执行(由于挂起)时被定义。
For example, a function expression:
例如,函数表达式:
// TypeError: undefined is not a function
functionOne();
var functionOne = function() {
console.log("Hello!");
};
And, a function declaration:
,一个函数声明:
// Outputs: "Hello!"
functionTwo();
function functionTwo() {
console.log("Hello!");
}
This also means you can't conditionally define functions using function declarations:
这也意味着您不能使用函数声明有条件地定义函数:
if (test) {
// Error or misbehavior
function functionThree() { doSomething(); }
}
The above actually defines functionThree
irrespective of test
's value — unless use strict
is in effect, in which case it simply raises an error.
以上实际上定义了function3,而不考虑测试的值——除非使用严格的方法,在这种情况下,它只会产生一个错误。
#2
1753
First I want to correct Greg: function abc(){}
is scoped too — the name abc
is defined in the scope where this definition is encountered. Example:
首先,我想纠正格雷格:函数abc(){}也是作用域的——在遇到这个定义的范围内定义abc。例子:
function xyz(){
function abc(){};
// abc is defined here...
}
// ...but not here
Secondly, it is possible to combine both styles:
其次,可以将两种风格结合起来:
var xyz = function abc(){};
xyz
is going to be defined as usual, abc
is undefined in all browsers but Internet Explorer — do not rely on it being defined. But it will be defined inside its body:
xyz将被定义为通常的,abc在所有浏览器中都没有定义,但是Internet Explorer—不要依赖它被定义。但它会在体内被定义:
var xyz = function abc(){
// xyz is visible here
// abc is visible here
}
// xyz is visible here
// abc is undefined here
If you want to alias functions on all browsers, use this kind of declaration:
如果您想在所有浏览器上使用别名,请使用以下声明:
function abc(){};
var xyz = abc;
In this case, both xyz
and abc
are aliases of the same object:
在这种情况下,xyz和abc都是同一个对象的别名:
console.log(xyz === abc); // prints "true"
One compelling reason to use the combined style is the "name" attribute of function objects (not supported by Internet Explorer). Basically when you define a function like
使用组合样式的一个令人信服的原因是函数对象的“name”属性(不支持Internet Explorer)。当你定义一个函数的时候。
function abc(){};
console.log(abc.name); // prints "abc"
its name is automatically assigned. But when you define it like
它的名字是自动分配的。但是当你定义它的时候。
var abc = function(){};
console.log(abc.name); // prints ""
its name is empty — we created an anonymous function and assigned it to some variable.
它的名称是空的——我们创建了一个匿名函数,并将其分配给某个变量。
Another good reason to use the combined style is to use a short internal name to refer to itself, while providing a long non-conflicting name for external users:
使用组合样式的另一个很好的理由是使用一个简短的内部名称来引用它本身,同时为外部用户提供一个长而非冲突的名称:
// Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
// Let it call itself recursively:
shortcut(n - 1);
// ...
// Let it pass itself as a callback:
someFunction(shortcut);
// ...
}
In the example above we can do the same with an external name, but it'll be too unwieldy (and slower).
在上面的例子中,我们可以用一个外部名称来做同样的事情,但是它太笨拙(而且更慢)。
(Another way to refer to itself is to use arguments.callee
, which is still relatively long, and not supported in the strict mode.)
另一种方法是使用参数。callee,它仍然相对较长,在严格的模式下不支持。
Deep down, JavaScript treats both statements differently. This is a function declaration:
在深层,JavaScript对这两个语句都有不同的处理。这是一个函数声明:
function abc(){}
abc
here is defined everywhere in the current scope:
这里的abc是在当前范围内的任何地方定义的:
// We can call it here
abc(); // Works
// Yet, it is defined down there.
function abc(){}
// We can call it again
abc(); // Works
Also, it hoisted through a return
statement:
此外,它还通过一份退货声明提出:
// We can call it here
abc(); // Works
return;
function abc(){}
This is a function expression:
这是一个函数表达式:
var xyz = function(){};
xyz
here is defined from the point of assignment:
这里的xyz是由作业点定义的:
// We can't call it here
xyz(); // UNDEFINED!!!
// Now it is defined
xyz = function(){}
// We can call it here
xyz(); // works
Function declaration vs. function expression is the real reason why there is a difference demonstrated by Greg.
函数声明与函数表达式是格雷格演示的差异的真正原因。
Fun fact:
有趣的事实:
var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"
Personally, I prefer the "function expression" declaration because this way I can control the visibility. When I define the function like
就个人而言,我更喜欢“函数表达式”声明,因为这样我可以控制可见性。当我定义函数的时候。
var abc = function(){};
I know that I defined the function locally. When I define the function like
我知道我在本地定义了函数。当我定义函数的时候。
abc = function(){};
I know that I defined it globally providing that I didn't define abc
anywhere in the chain of scopes. This style of definition is resilient even when used inside eval()
. While the definition
我知道,我在全球范围内定义了它,因为我没有在范围内的任何地方定义abc。这种类型的定义即使在eval()中使用时也是有弹性的。而定义
function abc(){};
depends on the context and may leave you guessing where it is actually defined, especially in the case of eval()
— the answer is: It depends on the browser.
取决于上下文,可能会让您猜测它实际上是在哪里定义的,特别是在eval()的情况下——答案是:它取决于浏览器。
#3
514
Here's the rundown on the standard forms that create functions: (Originally written for another question, but adapted after being moved into the canonical question.)
以下是创建函数的标准表单的纲要(最初是为另一个问题编写的,但在被转移到规范问题之后改编)。
Terms:
术语:
- ES5: ECMAScript 5th edition, 2009
- ES5: ECMAScript第五版,2009。
- ES2015: ECMAScript 2015 (also known as "ES6")
- ES2015: ECMAScript 2015(也被称为ES6)
The quick list:
快速列表:
-
Function Declaration
函数声明
-
"Anonymous"
function
Expression (which despite the term, sometimes create functions with names)“匿名”函数表达式(尽管有术语,有时会创建名称函数)
-
Named
function
Expression命名函数表达式
-
Accessor Function Initializer (ES5+)
访问器函数初始化(ES5 +)
-
Arrow Function Expression (ES2015+) (which, like anonymous function expressions, don't involve an explicit name, and yet can create functions with names)
箭头函数表达式(ES2015+)(它与匿名函数表达式一样,不涉及显式名称,但可以创建具有名称的函数)
-
Method Declaration in Object Initializer (ES2015+)
对象初始化器中的方法声明(ES2015+)
-
Constructor and Method Declarations in
class
(ES2015+)类的构造函数和方法声明(ES2015+)
Function Declaration
The first form is a function declaration, which looks like this:
第一个表单是一个函数声明,它看起来是这样的:
function x() {
console.log('x');
}
A function declaration is a declaration; it's not a statement or expression. As such, you don't follow it with a ;
(although doing so is harmless).
函数声明是一个声明;它不是一个陈述或表达。因此,你不会跟随它;(尽管这样做是无害的)。
A function declaration is processed when execution enters the context in which it appears, before any step-by-step code is executed. The function it creates is given a proper name (x
in the example above), and that name is put in the scope in which the declaration appears.
当执行进入其出现的上下文时,将处理函数声明,在执行任何分步代码之前。它创建的函数有一个适当的名称(上面示例中的x),并且该名称放在声明出现的范围内。
Because it's processed before any step-by-step code in the same context, you can do things like this:
因为它是在同一上下文中任何一步一步的代码之前处理的,你可以这样做:
x(); // Works even though it's above the declaration
function x() {
console.log('x');
}
Until ES2015, the spec didn't cover what a JavaScript engine should do if you put a function declaration inside a control structure like try
, if
, switch
, while
, etc., like this:
直到2015年,规范没有涵盖JavaScript引擎应该做的事情,如果您在控件结构中放入一个函数声明,如try、if、switch、while等,就像这样:
if (someCondition) {
function foo() { // <===== HERE THERE
} // <===== BE DRAGONS
}
And since they're processed before step-by-step code is run, it's tricky to know what to do when they're in a control structure.
而且由于它们是在一步一步的代码运行之前处理的,所以当它们处于控制结构中时,要知道该怎么做是很困难的。
Although doing this wasn't specified until ES2015, it was an allowable extension to support function declarations in blocks. Unfortunately (and inevitably), different engines did different things.
尽管在ES2015之前没有指定这样做,但它是支持块中的函数声明的允许扩展。不幸的是(不可避免地),不同的引擎做了不同的事情。
As of ES2015, the specification says what to do. In fact, it gives three separate things to do:
截止到2015年,规范规定了该做什么。事实上,它有三件事要做:
- If in loose mode not on a web browser, the JavaScript engine is supposed to do one thing
- 如果在松散模式下,而不是在web浏览器上,JavaScript引擎应该做一件事。
- If in loose mode on a web browser, the JavaScript engine is supposed to do something else
- 如果在web浏览器上使用松散模式,则JavaScript引擎应该执行其他操作。
- If in strict mode (browser or not), the JavaScript engine is supposed to do yet another thing
- 如果在严格的模式下(浏览器或非浏览器),JavaScript引擎应该做另一件事。
The rules for the loose modes are tricky, but in strict mode, function declarations in blocks are easy: They're local to the block (they have block scope, which is also new in ES2015), and they're hoisted to the top of the block. So:
松散模式的规则很复杂,但是在严格的模式下,块的函数声明很简单:它们是块的本地(它们有块作用域,在ES2015中也是新的),它们被提升到块的顶部。所以:
"use strict";
if (someCondition) {
foo(); // Works just fine
function foo() {
}
}
console.log(typeof foo); // "undefined" (`foo` is not in scope here
// because it's not in the same block)
"Anonymous" function
Expression
The second common form is called an anonymous function expression:
第二种常见形式称为匿名函数表达式:
var y = function () {
console.log('y');
};
Like all expressions, it's evaluated when it's reached in the step-by-step execution of the code.
和所有表达式一样,它是在代码逐步执行时进行评估的。
In ES5, the function this creates has no name (it's anonymous). In ES2015, the function is assigned a name if possible by inferring it from context. In the example above, the name would be y
. Something similar is done when the function is the value of a property initializer. (For details on when this happens and the rules, search for SetFunctionName
in the the specification — it appears all over the place.)
在ES5中,这个创建的函数没有名称(它是匿名的)。在ES2015中,如果可能的话,通过从上下文推断出该函数的名称。在上面的示例中,名称为y。当函数是属性初始值设定项的值时,类似的操作就完成了。(关于何时发生和规则的详细信息,请在规范中搜索SetFunctionName,它会出现在所有地方。)
Named function
Expression
The third form is a named function expression ("NFE"):
第三种形式是一个命名函数表达式(“NFE”):
var z = function w() {
console.log('zw')
};
The function this creates has a proper name (w
in this case). Like all expressions, this is evaluated when it's reached in the step-by-step execution of the code. The name of the function is not added to the scope in which the expression appears; the name is in scope within the function itself:
这个函数创建的函数有一个专有名称(在本例中为w)。就像所有表达式一样,在代码的逐步执行过程中进行评估。函数的名称不添加到表达式出现的范围;名称在函数本身的范围内:
var z = function w() {
console.log(typeof w); // "function"
};
console.log(typeof w); // "undefined"
Note that NFEs have frequently been a source of bugs for JavaScript implementations. IE8 and earlier, for instance, handle NFEs completely incorrectly, creating two different functions at two different times. Early versions of Safari had issues as well. The good news is that current versions of browsers (IE9 and up, current Safari) don't have those issues any more. (But as of this writing, sadly, IE8 remains in widespread use, and so using NFEs with code for the web in general is still problematic.)
注意,NFEs经常是JavaScript实现的bug源。例如,IE8和更早的时候,完全错误地处理NFEs,在两个不同的时间创建两个不同的函数。Safari的早期版本也有问题。好消息是目前的浏览器版本(IE9和最新的Safari浏览器)已经不再有这些问题了。(但遗憾的是,在撰写本文时,IE8仍在广泛使用,所以使用NFEs编写web代码仍然是个问题。)
Accessor Function Initializer (ES5+)
Sometimes functions can sneak in largely unnoticed; that's the case with accessor functions. Here's an example:
有时,功能可以悄无声息地潜入;这就是accessor函数的情况。这里有一个例子:
var obj = {
value: 0,
get f() {
return this.value;
},
set f(v) {
this.value = v;
}
};
console.log(obj.f); // 0
console.log(typeof obj.f); // "number"
Note that when I used the function, I didn't use ()
! That's because it's an accessor function for a property. We get and set the property in the normal way, but behind the scenes, the function is called.
注意,当我使用这个函数时,我没有使用()!这是因为它是属性的访问函数。我们以正常的方式获取和设置属性,但是在幕后,函数被调用。
You can also create accessor functions with Object.defineProperty
, Object.defineProperties
, and the lesser-known second argument to Object.create
.
您还可以使用Object.defineProperty、Object.defineProperties和不太知名的第二个参数创建accessor函数。
Arrow Function Expression (ES2015+)
ES2015 brings us the arrow function. Here's one example:
ES2015给我们带来了箭头函数。这里有一个例子:
var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6
See that n => n * 2
thing hiding in the map()
call? That's a function.
看到在map()调用中隐藏的n => n * 2的东西吗?这是一个函数。
A couple of things about arrow functions:
关于箭头函数有几点
-
They don't have their own
this
. Instead, they close over thethis
of the context where they're defined. (They also close overarguments
and, where relevant,super
.) This means that thethis
within them is the same as thethis
where they're created, and cannot be changed.他们没有自己的这个。相反,它们会在定义它们的上下文中结束。(他们也会结束争论,并在相关的情况下超赞。)这意味着在它们内部的这个和它们创建的地方是一样的,并且不能被改变。
-
As you'll have noticed with the above, you don't use the keyword
function
; instead, you use=>
.正如您在上面所看到的,您不使用关键字函数;相反,您使用= >。
The n => n * 2
example above is one form of them. If you have multiple arguments to pass the function, you use parens:
上面的n => n * 2是其中一种形式。如果有多个参数传递函数,则使用parens:
var a = [1, 2, 3];
var b = a.map((n, i) => n * i);
console.log(b.join(", ")); // 0, 2, 6
(Remember that Array#map
passes the entry as the first argument, and the index as the second.)
(请记住,数组#map将条目作为第一个参数传递,而索引作为第二个参数。)
In both cases, the body of the function is just an expression; the function's return value will automatically be the result of that expression (you don't use an explicit return
).
在这两种情况下,函数的主体只是一个表达式;函数的返回值将自动成为该表达式的结果(您不使用显式返回)。
If you're doing more than just a single expression, use {}
and an explicit return
(if you need to return a value), as normal:
如果您正在做的不仅仅是一个表达式,使用{}和显式返回(如果您需要返回一个值),这是正常的:
var a = [
{first: "Joe", last: "Bloggs"},
{first: "Albert", last: "Bloggs"},
{first: "Mary", last: "Albright"}
];
a = a.sort((a, b) => {
var rv = a.last.localeCompare(b.last);
if (rv === 0) {
rv = a.first.localeCompare(b.first);
}
return rv;
});
console.log(JSON.stringify(a));
The version without { ... }
is called an arrow function with an expression body or concise body. (Also: A concise arrow function.) The one with { ... }
defining the body is an arrow function with a function body. (Also: A verbose arrow function.)
没有{…}被称为一个带有表达式体或简洁主体的箭头函数。(还有一个简洁的箭头函数。)有{…定义主体是一个带有函数体的箭头函数。(还有一个详细的箭头函数。)
Method Declaration in Object Initializer (ES2015+)
ES2015 allows a shorter form of declaring a property that references a function; it looks like this:
ES2015允许更短的形式声明引用函数的属性;它看起来像这样:
var o = {
foo() {
}
};
the equivalent in ES5 and earlier would be:
在ES5和更早时的等效项是:
var o = {
foo: function foo() {
}
};
Constructor and Method Declarations in class
(ES2015+)
ES2015 brings us class
syntax, including declared constructors and methods:
ES2015带来了类语法,包括声明的构造函数和方法:
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName() {
return this.firstName + " " + this.lastName;
}
}
There are two function declarations above: One for the constructor, which gets the name Person
, and one for getFullName
, which is a function assigned to Person.prototype
.
上面有两个函数声明:一个用于构造函数,一个用于获取名称,另一个用于getFullName,这是一个分配给Person.prototype的函数。
#4
125
Speaking about the global context, both, the var
statement and a FunctionDeclaration
at the end will create a non-deleteable property on the global object, but the value of both can be overwritten.
在谈到全局上下文时,两端的var语句和函数声明将在全局对象上创建一个不可删除的属性,但是两者的值都可以被覆盖。
The subtle difference between the two ways is that when the Variable Instantiation process runs (before the actual code execution) all identifiers declared with var
will be initialized with undefined
, and the ones used by the FunctionDeclaration
's will be available since that moment, for example:
这两种方法之间的细微差别在于,当变量实例化进程运行(在实际的代码执行之前)时,使用var声明的所有标识符都将被初始化,并没有定义,而FunctionDeclaration所使用的标识符将从那一时刻开始使用,例如:
alert(typeof foo); // 'function', it's already available
alert(typeof bar); // 'undefined'
function foo () {}
var bar = function () {};
alert(typeof bar); // 'function'
The assignment of the bar
FunctionExpression
takes place until runtime.
bar FunctionExpression的赋值在运行时发生。
A global property created by a FunctionDeclaration
can be overwritten without any problems just like a variable value, e.g.:
由FunctionDeclaration创建的全局属性可以被重写,而不需要像变量值一样的问题。
function test () {}
test = null;
Another obvious difference between your two examples is that the first function doesn't have a name, but the second has it, which can be really useful when debugging (i.e. inspecting a call stack).
两个示例之间的另一个明显区别是,第一个函数没有名称,但是第二个函数有它,这在调试(即检查调用堆栈)时非常有用。
About your edited first example (foo = function() { alert('hello!'); };
), it is an undeclared assignment, I would highly encourage you to always use the var
keyword.
关于您编辑的第一个示例(foo = function() {alert('hello!');),它是一个未声明的赋值,我强烈建议您始终使用var关键字。
With an assignment, without the var
statement, if the referenced identifier is not found in the scope chain, it will become a deleteable property of the global object.
有了赋值,没有var语句,如果在范围链中没有找到引用的标识符,它将成为全局对象的可删除属性。
Also, undeclared assignments throw a ReferenceError
on ECMAScript 5 under Strict Mode.
此外,未声明的作业在严格模式下对ECMAScript 5抛出一个参考错误。
A must read:
一个必须阅读:
- Named function expressions demystified
- 命名函数表达式的启发
Note: This answer has been merged from another question, in which the major doubt and misconception from the OP was that identifiers declared with a FunctionDeclaration
, couldn't be overwritten which is not the case.
注意:这个答案已经与另一个问题合并了,在这个问题中,OP的主要疑问和误解是使用FunctionDeclaration声明的标识符,不能被覆盖,但事实并非如此。
#5
105
The two code snippets you've posted there will, for almost all purposes, behave the same way.
您在那里发布的两个代码片段几乎都将以相同的方式运行。
However, the difference in behaviour is that with the first variant (var functionOne = function() {}
), that function can only be called after that point in the code.
然而,行为的不同之处在于,在第一个变量(var functionOne = function(){})中,该函数只能在代码中的那个点之后调用。
With the second variant (function functionTwo()
), the function is available to code that runs above where the function is declared.
对于第二个变体(函数function2()),函数可以在函数声明的地方运行。
This is because with the first variant, the function is assigned to the variable foo
at run time. In the second, the function is assigned to that identifier, foo
, at parse time.
这是因为在第一个变量中,函数在运行时被分配给变量foo。在第二种情况下,函数被分配给该标识符,foo,在解析时间。
More technical information
更多的技术信息
JavaScript has three ways of defining functions.
JavaScript有三种定义函数的方法。
- Your first snippet shows a function expression. This involves using the "function" operator to create a function - the result of that operator can be stored in any variable or object property. The function expression is powerful that way. The function expression is often called an "anonymous function", because it does not have to have a name,
- 您的第一个代码片段显示了一个函数表达式。这涉及使用“函数”操作符来创建一个函数——该操作符的结果可以存储在任何变量或对象属性中。函数表达式的功能非常强大。函数表达式通常被称为“匿名函数”,因为它不必有名称,
- Your second example is a function declaration. This uses the "function" statement to create a function. The function is made available at parse time and can be called anywhere in that scope. You can still store it in a variable or object property later.
- 第二个示例是函数声明。这使用“函数”语句来创建一个函数。该函数在解析时可用,可以在该范围内的任何地方调用。您仍然可以在稍后将其存储在一个变量或对象属性中。
- The third way of defining a function is the "Function()" constructor, which is not shown in your original post. It's not recommended to use this as it works the same way as
eval()
, which has its problems. - 定义函数的第三种方法是“function()”构造函数,它在原始的post中没有显示。不建议使用它,因为它的工作方式与eval()相同,这有它的问题。
#6
85
A better explanation to Greg's answer
对格雷格的回答有更好的解释。
functionTwo();
function functionTwo() {
}
Why no error? We were always taught that expressions are executed from top to bottom(??)
为什么没有错误?我们一直都知道表达式是从上到下执行的(??)
Because:
Function declarations and variable declarations are always moved (
hoisted
) invisibly to the top of their containing scope by the JavaScript interpreter. Function parameters and language-defined names are, obviously, already there. ben cherry函数声明和变量声明总是被JavaScript解释器移到其包含范围的顶部。显然,函数参数和语言定义的名称已经存在。本樱桃
This means that code like this:
这意味着这样的代码:
functionOne(); --------------- var functionOne;
| is actually | functionOne();
var functionOne = function(){ | interpreted |-->
}; | like | functionOne = function(){
--------------- };
Notice that the assignment portion of the declarations were not hoisted. Only the name is hoisted.
请注意,声明的赋值部分没有挂起。只有这个名字被吊起来了。
But in the case with function declarations, the entire function body will be hoisted as well:
但是在函数声明的情况下,整个函数体也将被提升:
functionTwo(); --------------- function functionTwo() {
| is actually | };
function functionTwo() { | interpreted |-->
} | like | functionTwo();
---------------
#7
80
Other commenters have already covered the semantic difference of the two variants above. I wanted to note a stylistic difference: Only the "assignment" variation can set a property of another object.
其他评论者已经涵盖了上述两种变体的语义差异。我想要注意一种风格上的差异:只有“赋值”变体可以设置另一个对象的属性。
I often build JavaScript modules with a pattern like this:
我经常使用这样的模式构建JavaScript模块:
(function(){
var exports = {};
function privateUtil() {
...
}
exports.publicUtil = function() {
...
};
return exports;
})();
With this pattern, your public functions will all use assignment, while your private functions use declaration.
有了这个模式,您的公共函数将全部使用赋值,而您的私有函数使用声明。
(Note also that assignment should require a semicolon after the statement, while declaration prohibits it.)
(注意,在声明之后,赋值应该要求分号,而声明则禁止。)
#8
66
An illustration of when to prefer the first method to the second one is when you need to avoid overriding a function's previous definitions.
当您需要避免重写函数以前的定义时,说明何时优先使用第一个方法。
With
与
if (condition){
function myfunction(){
// Some code
}
}
, this definition of myfunction
will override any previous definition, since it will be done at parse-time.
这个myfunction的定义将覆盖任何以前的定义,因为它将在parse-time中完成。
While
而
if (condition){
var myfunction = function (){
// Some code
}
}
does the correct job of defining myfunction
only when condition
is met.
只有在条件满足时才定义myfunction的正确工作。
#9
53
An important reason is to add one and only one variable as the "Root" of your namespace...
一个重要的原因是添加一个变量作为名称空间的“根”。
var MyNamespace = {}
MyNamespace.foo= function() {
}
or
或
var MyNamespace = {
foo: function() {
},
...
}
There are many techniques for namespacing. It's become more important with the plethora of JavaScript modules available.
有许多用于命名空间的技术。对于大量可用的JavaScript模块,它变得更加重要。
Also see How do I declare a namespace in JavaScript?
还可以看到如何在JavaScript中声明名称空间?
#10
45
Hoisting is the JavaScript interpreter’s action of moving all variable and function declarations to the top of the current scope.
提升是JavaScript解释器的动作,它将所有变量和函数声明移动到当前范围的顶部。
However, only the actual declarations are hoisted. by leaving assignments where they are.
但是,只有实际的声明被挂起。把任务交给他们。
- variable's/Function's declared inside the page are global can access anywhere in that page.
- 在页面中声明的变量的/函数是全局的,可以访问该页面中的任何位置。
- variable's/Functions declared inside the function are having local scope. means they are available/accessed inside the function body (scope), they are not available outside the function body.
- 函数内声明的变量/函数具有局部范围。表示它们在函数体(范围)内可用/访问,它们在函数体之外是不可用的。
变量
Javascript is called loosely typed language. Which means Javascript variables can hold value of any Data-Type. Javascript automatically takes care of changing the variable-type based on the value/literal provided during runtime.
Javascript被称为松散类型语言。这意味着Javascript变量可以保存任何数据类型的值。Javascript会自动地根据运行时提供的值/文字来改变变量类型。
global_Page = 10; var global_Page; « undefined
« Integer literal, Number Type. ------------------- global_Page = 10; « Number
global_Page = 'Yash'; | Interpreted | global_Page = 'Yash'; « String
« String literal, String Type. « AS « global_Page = true; « Boolean
var global_Page = true; | | global_Page = function (){ « function
« Boolean Type ------------------- var local_functionblock; « undefined
global_Page = function (){ local_functionblock = 777;« Number
var local_functionblock = 777; };
// Assigning function as a data.
};
Function
函数
function Identifier_opt ( FormalParameterList_opt ) {
FunctionBody | sequence of statements
« return; Default undefined
« return 'some data';
}
- functions declared inside the page are hoisted to top of the page having global access.
- 页面内声明的函数将被提升到具有全局访问权的页面顶部。
- functions declared inside the function-block are hoisted to top of the block.
- 函数块内部声明的函数被提升到块的顶部。
-
Default return value of function is 'undefined', Variable declaration default value also 'undefined'
函数的默认返回值是“未定义的”,变量声明默认值也“未定义”
Scope with respect to function-block global. Scope with respect to page undefined | not available.
Function Declaration
函数声明
function globalAccess() { function globalAccess() {
} ------------------- }
globalAccess(); | | function globalAccess() { « Re-Defined / overridden.
localAccess(); « Hoisted As « function localAccess() {
function globalAccess() { | | }
localAccess(); ------------------- localAccess(); « function accessed with in globalAccess() only.
function localAccess() { }
} globalAccess();
} localAccess(); « ReferenceError as the function is not defined
Function Expression
函数表达式
10; « literal
(10); « Expression (10).toString() -> '10'
var a;
a = 10; « Expression var a.toString() -> '10'
(function invoke() { « Expression Function
console.log('Self Invoking'); (function () {
}); }) () -> 'Self Invoking'
var f;
f = function (){ « Expression var Function
console.log('var Function'); f () -> 'var Function'
};
Function assigned to variable Example:
分配给变量示例的函数:
(function selfExecuting(){
console.log('IIFE - Immediately-Invoked Function Expression');
}());
var anonymous = function (){
console.log('anonymous function Expression');
};
var namedExpression = function for_InternalUSE(fact){
if(fact === 1){
return 1;
}
var localExpression = function(){
console.log('Local to the parent Function Scope');
};
globalExpression = function(){
console.log('creates a new global variable, then assigned this function.');
};
//return; //undefined.
return fact * for_InternalUSE( fact - 1);
};
namedExpression();
globalExpression();
javascript interpreted as
javascript解释为
var anonymous;
var namedExpression;
var globalExpression;
anonymous = function (){
console.log('anonymous function Expression');
};
namedExpression = function for_InternalUSE(fact){
var localExpression;
if(fact === 1){
return 1;
}
localExpression = function(){
console.log('Local to the parent Function Scope');
};
globalExpression = function(){
console.log('creates a new global variable, then assigned this function.');
};
return fact * for_InternalUSE( fact - 1); // DEFAULT UNDEFINED.
};
namedExpression(10);
globalExpression();
You can check function declaration, expression test over different browser's using jsperf Test Runner
您可以使用jsperf测试运行器检查函数声明、表达式测试。
ES5 Constructor Function Classes: Function objects created using Function.prototype.bind
ES5构造函数类:使用函数创建的函数对象。
JavaScript treats functions as first-class objects, so being an object, you can assign properties to a function.
JavaScript将函数视为一级对象,因此作为对象,可以将属性赋给函数。
function Shape(id) { // Function Declaration
this.id = id;
};
// Adding a prototyped method to a function.
Shape.prototype.getID = function () {
return this.id;
};
Shape.prototype.setID = function ( id ) {
this.id = id;
};
var expFn = Shape; // Function Expression
var funObj = new Shape( ); // Function Object
funObj.hasOwnProperty('prototype'); // false
funObj.setID( 10 );
console.log( funObj.getID() ); // 10
ES6 introduced Arrow function: An arrow function expression has a shorter syntax, they are best suited for non-method functions, and they cannot be used as constructors.
ES6引入了箭头函数:一个箭头函数表达式的语法较短,它们最适合于非方法函数,它们不能作为构造函数使用。
ArrowFunction : ArrowParameters => ConciseBody
.ArrowFunction: ArrowParameters => ConciseBody。
const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; }; console.log( fn(2) ); // Even console.log( fn(3) ); // Odd
#11
32
I'm adding my own answer just because everyone else has covered the hoisting part thoroughly.
我只是在加上我自己的答案,因为其他所有人都把吊装部分完全盖住了。
I've wondered about which way is better for a long while now, and thanks to http://jsperf.com now I know :)
我一直在想,这条路在很长一段时间内会变得更好,多亏了http://jsperf.com,现在我知道了:
Function declarations are faster, and that's what really matters in web dev right? ;)
函数声明更快,这才是web开发中真正重要的东西?,)
#12
29
A function declaration and a function expression assigned to a variable behave the same once the binding is established.
当绑定建立时,赋值给一个变量的函数声明和函数表达式。
There is a difference however at how and when the function object is actually associated with its variable. This difference is due to the mechanism called variable hoisting in JavaScript.
然而,当函数对象与它的变量相关联时,有一个不同之处。这种差异是由于在JavaScript中被称为变量提升的机制。
Basically, all function declarations and variable declarations are hoisted to the top of the function in which the declaration occurs (this is why we say that JavaScript has function scope).
基本上,所有函数声明和变量声明都被提升到声明发生的函数的顶部(这就是为什么我们说JavaScript有函数作用域)。
-
When a function declaration is hoisted, the function body "follows" so when the function body is evaluated, the variable will immediately be bound to a function object.
当函数声明被挂起时,函数体“跟随”,当函数体被求值时,变量将立即被绑定到一个函数对象。
-
When a variable declaration is hoisted, the initialization does not follow, but is "left behind". The variable is initialized to
undefined
at the start of the function body, and will be assigned a value at its original location in the code. (Actually, it will be assigned a value at every location where a declaration of a variable with the same name occurs.)当一个变量声明被升起时,初始化不会跟随,而是被“留下”。变量在函数体开始时初始化为未定义,并将在代码的原始位置赋值。(实际上,它将在每个位置上分配一个值,在该位置上出现一个同名变量的声明。)
The order of hoisting is also important: function declarations take precedence over variable declarations with the same name, and the last function declaration takes precedence over previous function declarations with the same name.
提升的顺序也很重要:函数声明优先于具有相同名称的变量声明,而最后一个函数声明优先于具有相同名称的前一个函数声明。
Some examples...
一些例子…
var foo = 1;
function bar() {
if (!foo) {
var foo = 10 }
return foo; }
bar() // 10
Variable foo
is hoisted to the top of the function, initialized to undefined
, so that !foo
is true
, so foo
is assigned 10
. The foo
outside of bar
's scope plays no role and is untouched.
变量foo被提升到函数的顶部,初始化为未定义的,因此,foo是true,所以foo被赋值为10。在bar的范围之外的foo没有作用,没有被修改。
function f() {
return a;
function a() {return 1};
var a = 4;
function a() {return 2}}
f()() // 2
function f() {
return a;
var a = 4;
function a() {return 1};
function a() {return 2}}
f()() // 2
Function declarations take precedence over variable declarations, and the last function declaration "sticks".
函数声明优先于变量声明,最后一个函数声明“棒”。
function f() {
var a = 4;
function a() {return 1};
function a() {return 2};
return a; }
f() // 4
In this example a
is initialized with the function object resulting from evaluating the second function declaration, and then is assigned 4
.
在这个示例中,使用函数对象初始化了一个函数,结果是对第二个函数声明进行了评估,然后将其赋值为4。
var a = 1;
function b() {
a = 10;
return;
function a() {}}
b();
a // 1
Here the function declaration is hoisted first, declaring and initializing variable a
. Next, this variable is assigned 10
. In other words: the assignment does not assign to outer variable a
.
这里首先提升函数声明,声明和初始化变量a。接下来,这个变量被赋值为10。换句话说:赋值不能赋给外部变量a。
#13
26
The first example is a function declaration:
第一个示例是函数声明:
function abc(){}
The second example is a function expression:
第二个例子是函数表达式:
var abc = function() {};
The main difference is how they are hoisted (lifted and declared). In the first example, the whole function declaration is hoisted. In the second example only the var 'abc' is hoisted, its value (the function) will be undefined, and the function itself remains at the position that it is declared.
主要的区别是它们是如何被提升的(举起和声明)。在第一个示例中,将挂起整个函数声明。在第二个示例中,只有var 'abc'被挂起,它的值(函数)将没有定义,函数本身保留在声明的位置上。
To put it simply:
简而言之:
//this will work
abc(param);
function abc(){}
//this would fail
abc(param);
var abc = function() {}
To study more about this topic I strongly recommend you this link
为了进一步研究这个话题,我强烈推荐你这个链接。
#14
25
In terms of code maintenance cost, named functions are more preferable:
就代码维护成本而言,命名函数更可取:
- Independent from the place where they are declared (but still limited by scope).
- 独立于被声明的地方(但仍受范围限制)。
- More resistant to mistakes like conditional initialization (you are still able to override if wanted to).
- 更能抵抗像条件初始化这样的错误(如果需要,您仍然可以重写)。
- The code becomes more readable by allocating local functions separately of scope functionality. Usually in the scope the functionality goes first, followed by declarations of local functions.
- 通过将局部函数单独分配到作用域功能,代码变得更加可读。通常在功能的范围内,然后是局部函数的声明。
- In a debugger you will clearly see the function name on the call stack instead of an "anonymous/evaluated" function.
- 在调试器中,您将清楚地看到调用堆栈上的函数名,而不是“匿名/评估”函数。
I suspect more PROS for named functions are follow. And what is listed as an advantage of named functions is a disadvantage for anonymous ones.
我怀疑有更多关于命名函数的好处。命名函数的优点是匿名函数的缺点。
Historically, anonymous functions appeared from the inability of JavaScript as a language to list members with named functions:
从历史上看,匿名函数出现的原因是JavaScript无法作为一种语言来列出具有命名功能的成员:
{
member:function() { /* How do I make "this.member" a named function? */
}
}
#15
22
I use the variable approach in my code for a very specific reason, the theory of which has been covered in an abstract way above, but an example might help some people like me, with limited JavaScript expertise.
我在代码中使用了变量方法,这是一个非常具体的原因,它的理论已经以一种抽象的方式覆盖了,但是一个例子可能会帮助一些像我这样的人,使用有限的JavaScript技术。
I have code that I need to run with 160 independently-designed brandings. Most of the code is in shared files, but branding-specific stuff is in a separate file, one for each branding.
我有代码,我需要运行160个独立设计的品牌。大多数代码都在共享文件中,但是特定于品牌的东西在一个单独的文件中,一个用于每个品牌。
Some brandings require specific functions, and some do not. Sometimes I have to add new functions to do new branding-specific things. I am happy to change the shared coded, but I don't want to have to change all 160 sets of branding files.
有些品牌需要特定的功能,有些则不需要。有时候,我需要添加一些新的功能来做一些新的特定品牌的事情。我很乐意更改共享代码,但我不想更改所有160套品牌文件。
By using the variable syntax, I can declare the variable (a function pointer essentially) in the shared code and either assign a trivial stub function, or set to null.
通过使用变量语法,我可以在共享代码中声明变量(本质上是一个函数指针),并分配一个微不足道的存根函数,或者设置为null。
The one or two brandings that need a specific implementation of the function can then define their version of the function and assign this to the variable if they want, and the rest do nothing. I can test for a null function before I execute it in the shared code.
需要特定实现功能的一个或两个brandings可以定义函数的版本,并将其分配给变量,其余的则什么都不做。在执行共享代码之前,我可以测试一个空函数。
From people's comments above, I gather it may be possible to redefine a static function too, but I think the variable solution is nice and clear.
从上面的人的评论中,我也可以重新定义一个静态函数,但是我认为这个变量的解决方案是很清晰的。
#16
19
In computer science terms, we talk about anonymous functions and named functions. I think the most important difference is that an anonymous function is not bound to an name, hence the name anonymous function. In JavaScript it is a first class object dynamically declared at runtime.
在计算机科学术语中,我们讨论匿名函数和命名函数。我认为最重要的区别是匿名函数不受名称的约束,因此命名为匿名函数。在JavaScript中,它是在运行时动态声明的第一个类对象。
For more information on anonymous functions and lambda calculus, Wikipedia is a good start (http://en.wikipedia.org/wiki/Anonymous_function).
关于匿名函数和lambda微积分的更多信息,*是一个很好的开始。
#17
19
Greg's Answer is good enough, but I still would like to add something to it that I learned just now watching Douglas Crockford's videos.
格雷格的回答已经够好了,但我还是想给它添加一些东西,我刚刚才了解到道格拉斯·克罗克福德(Douglas Crockford)的视频。
Function expression:
函数表达式:
var foo = function foo() {};
Function statement:
函数声明:
function foo() {};
The function statement is just a shorthand for var
statement with a function
value.
函数语句只是具有函数值的var语句的简写。
So
所以
function foo() {};
expands to
扩大到
var foo = function foo() {};
Which expands further to:
进一步扩大:
var foo = undefined;
foo = function foo() {};
And they are both hoisted to the top of the code.
它们都被提升到了代码的顶端。
#18
16
@EugeneLazutkin gives an example where he names an assigned function to be able to use shortcut()
as an internal reference to itself. John Resig gives another example - copying a recursive function assigned to another object in his Learning Advanced Javascript tutorial. While assigning functions to properties isn't strictly the question here, I recommend actively trying the tutorial out - run the code by clicking the button in the upper right corner, and double click the code to edit to your liking.
@EugeneLazutkin给出了一个例子,他将一个指定的函数命名为可以使用快捷方式()作为内部引用。John Resig给出了另一个例子——在他学习的高级Javascript教程中,复制一个递归函数给另一个对象。虽然在这里不严格地将函数分配给属性,但我建议您积极地尝试一下教程——通过单击右上角的按钮来运行代码,双击代码以编辑您喜欢的代码。
Examples from the tutorial: recursive calls in yell()
:
本教程中的示例:yell()中的递归调用:
Tests fail when the original ninja object is removed. (page 13)
当原始的忍者对象被移除时,测试失败。(13页)
var ninja = {
yell: function(n){
return n > 0 ? ninja.yell(n-1) + "a" : "hiy";
}
};
assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." );
var samurai = { yell: ninja.yell };
var ninja = null;
try {
samurai.yell(4);
} catch(e){
assert( false, "Uh, this isn't good! Where'd ninja.yell go?" );
}
If you name the function that will be called recursively, the tests will pass. (page 14)
如果您命名将被递归调用的函数,则测试将通过。(14页)
var ninja = {
yell: function yell(n){
return n > 0 ? yell(n-1) + "a" : "hiy";
}
};
assert( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" );
var samurai = { yell: ninja.yell };
var ninja = {};
assert( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." );
#19
13
Another difference that is not mentioned in the other answers is that if you use the anonymous function
另一个不同之处是如果你使用匿名函数。
var functionOne = function() {
// Some code
};
and use that as a constructor as in
并将其用作构造函数。
var one = new functionOne();
then one.constructor.name
will not be defined. Function.name
is non-standard but is supported by Firefox, Chrome, other Webkit-derived browsers and IE 9+.
然后one.structor.name将不被定义。名称是不标准的,但由Firefox、Chrome、其他webkit派生的浏览器和ie9 +支持。
With
与
function functionTwo() {
// Some code
}
two = new functionTwo();
it is possible to retrieve the name of the constructor as a string with two.constructor.name
.
可以将构造函数的名称检索为带有two.constructor.name的字符串。
#20
13
If you would use those functions to create objects, you would get:
如果你使用这些函数来创建对象,你会得到:
var objectOne = new functionOne();
console.log(objectOne.__proto__); // prints "Object {}" because constructor is an anonymous function
var objectTwo = new functionTwo();
console.log(objectTwo.__proto__); // prints "functionTwo {}" because constructor is a named function
#21
13
I'm listing out the differences below:
我列出了下面的不同之处:
-
A function declaration can be placed anywhere in the code. Even if it is invoked before the definition appears in code, it gets executed as function declaration is committed to memory or in a way it is hoisted up, before any other code in the page starts execution.
函数声明可以放在代码的任何位置。即使在定义出现在代码中之前被调用,它也会被执行为函数声明,它会被提交到内存中,或者在页面中任何其他代码开始执行之前被提升。
Take a look at the function below:
看一下下面的函数:
function outerFunction() { function foo() { return 1; } return foo(); function foo() { return 2; } } alert(outerFunction()); // Displays 2
This is because, during execution, it looks like:-
这是因为在执行过程中,它看起来是这样的:-。
function foo() { // The first function declaration is moved to top return 1; } function foo() { // The second function declaration is moved to top return 2; } function outerFunction() { return foo(); } alert(outerFunction()); //So executing from top to bottom, //the last foo() returns 2 which gets displayed
A function expression, if not defined before calling it, will result in an error. Also, here the function definition itself is not moved to the top or committed to memory like in the function declarations. But the variable to which we assign the function gets hoisted up and undefined gets assigned to it.
函数表达式(如果在调用之前没有定义)将导致错误。同样,在这里,函数定义本身并没有移动到顶部,也不像在函数声明中那样提交到内存。但是我们分配函数的变量被提升了,而未定义的变量被赋值给它。
Same function using function expressions:
同样的函数使用函数表达式:
function outerFunction() { var foo = function() { return 1; } return foo(); var foo = function() { return 2; } } alert(outerFunction()); // Displays 1
This is because during execution, it looks like:
这是因为在执行过程中,它看起来是这样的:
function outerFunction() { var foo = undefined; var foo = undefined; foo = function() { return 1; }; return foo (); foo = function() { // This function expression is not reachable return 2; }; } alert(outerFunction()); // Displays 1
-
It is not safe to write function declarations in non-function blocks like if because they won't be accessible.
在非功能块中编写函数声明是不安全的,因为它们无法访问。
if (test) { function x() { doSomething(); } }
-
Named function expression like the one below, may not work in Internet Explorer browsers prior to version 9.
命名函数表达式如下所示,在版本9之前可能无法在Internet Explorer浏览器中工作。
var today = function today() {return new Date()}
#22
12
The first one (function doSomething(x)) should be part of an object notation.
第一个(函数doSomething(x))应该是对象表示法的一部分。
The second one (var doSomething = function(x){ alert(x);}
) is simply creating an anonymous function and assigning it to a variable, doSomething
. So doSomething() will call the function.
第二个(var doSomething = function(x){alert(x);})只是创建一个匿名函数,并将其分配给一个变量doSomething。doSomething()会调用函数。
You may want to know what a function declaration and function expression is.
您可能想知道函数声明和函数表达式是什么。
A function declaration defines a named function variable without requiring variable assignment. Function declarations occur as standalone constructs and cannot be nested within non-function blocks.
函数声明定义了一个命名函数变量,而不需要变量赋值。函数声明作为独立的结构出现,不能嵌套在非功能块中。
function foo() {
return 3;
}
ECMA 5 (13.0) defines the syntax as
function Identifier ( FormalParameterListopt ) { FunctionBody }ECMA 5(13.0)将语法定义为函数标识符(FormalParameterListopt) {FunctionBody}
In above condition the function name is visible within its scope and the scope of its parent (otherwise it would be unreachable).
在上述条件下,函数名在其作用域及其父对象的范围内可见(否则将不可访问)。
And in a function expression
在函数表达式中。
A function expression defines a function as a part of a larger expression syntax (typically a variable assignment ). Functions defined via functions expressions can be named or anonymous. Function expressions should not start with “function”.
函数表达式将函数定义为更大的表达式语法的一部分(通常是变量赋值)。通过函数表达式定义的函数可以命名或匿名。函数表达式不应该以“函数”开头。
// Anonymous function expression
var a = function() {
return 3;
}
// Named function expression
var a = function foo() {
return 3;
}
// Self-invoking function expression
(function foo() {
alert("hello!");
})();
ECMA 5 (13.0) defines the syntax as
function Identifieropt ( FormalParameterListopt ) { FunctionBody }ECMA 5(13.0)将语法定义为函数标识符(FormalParameterListopt) {FunctionBody}
#23
10
In light of the "named functions show up in stack traces" argument, modern JavaScript engines are actually quite capable of representing anonymous functions.
根据“在堆栈跟踪中显示的命名函数”的观点,现代JavaScript引擎实际上很有能力表示匿名函数。
As of this writing, V8, SpiderMonkey, Chakra and Nitro always refer to named functions by their names. They almost always refer to an anonymous function by its identifier if it has one.
在这篇文章中,V8、SpiderMonkey、Chakra和Nitro总是以它们的名字命名函数。如果有一个匿名函数,它们几乎总是引用它的标识符。
SpiderMonkey can figure out the name of an anonymous function returned from another function. The rest can't.
SpiderMonkey可以计算出从另一个函数返回的匿名函数的名称。剩下的不能。
If you really, really wanted your iterator and success callbacks to show up in the trace, you could name those too...
如果你真的想要你的迭代器和成功回调显示在跟踪中,你也可以命名它们。
[].forEach(function iterator() {});
But for the most part it's not worth stressing over.
但在很大程度上,这并不值得强调。
Harness (Fiddle)
'use strict';
var a = function () {
throw new Error();
},
b = function b() {
throw new Error();
},
c = function d() {
throw new Error();
},
e = {
f: a,
g: b,
h: c,
i: function () {
throw new Error();
},
j: function j() {
throw new Error();
},
k: function l() {
throw new Error();
}
},
m = (function () {
return function () {
throw new Error();
};
}()),
n = (function () {
return function n() {
throw new Error();
};
}()),
o = (function () {
return function p() {
throw new Error();
};
}());
console.log([a, b, c].concat(Object.keys(e).reduce(function (values, key) {
return values.concat(e[key]);
}, [])).concat([m, n, o]).reduce(function (logs, func) {
try {
func();
} catch (error) {
return logs.concat('func.name: ' + func.name + '\n' +
'Trace:\n' +
error.stack);
// Need to manually log the error object in Nitro.
}
}, []).join('\n\n'));
V8
func.name:
Trace:
Error
at a (http://localhost:8000/test.js:4:11)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: b
Trace:
Error
at b (http://localhost:8000/test.js:7:15)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: d
Trace:
Error
at d (http://localhost:8000/test.js:10:15)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name:
Trace:
Error
at a (http://localhost:8000/test.js:4:11)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: b
Trace:
Error
at b (http://localhost:8000/test.js:7:15)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: d
Trace:
Error
at d (http://localhost:8000/test.js:10:15)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name:
Trace:
Error
at e.i (http://localhost:8000/test.js:17:19)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: j
Trace:
Error
at j (http://localhost:8000/test.js:20:19)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: l
Trace:
Error
at l (http://localhost:8000/test.js:23:19)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name:
Trace:
Error
at http://localhost:8000/test.js:28:19
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: n
Trace:
Error
at n (http://localhost:8000/test.js:33:19)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27
func.name: p
Trace:
Error
at p (http://localhost:8000/test.js:38:19)
at http://localhost:8000/test.js:47:9
at Array.reduce (native)
at http://localhost:8000/test.js:44:27 test.js:42
SpiderMonkey
func.name:
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name:
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name:
Trace:
e.i@http://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: j
Trace:
j@http://localhost:8000/test.js:20:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: l
Trace:
l@http://localhost:8000/test.js:23:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name:
Trace:
m</<@http://localhost:8000/test.js:28:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: n
Trace:
n@http://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
func.name: p
Trace:
p@http://localhost:8000/test.js:38:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1
Chakra
func.name: undefined
Trace:
Error
at a (http://localhost:8000/test.js:4:5)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at b (http://localhost:8000/test.js:7:9)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at d (http://localhost:8000/test.js:10:9)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at a (http://localhost:8000/test.js:4:5)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at b (http://localhost:8000/test.js:7:9)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at d (http://localhost:8000/test.js:10:9)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at e.i (http://localhost:8000/test.js:17:13)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at j (http://localhost:8000/test.js:20:13)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at l (http://localhost:8000/test.js:23:13)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at Anonymous function (http://localhost:8000/test.js:28:13)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at n (http://localhost:8000/test.js:33:13)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
func.name: undefined
Trace:
Error
at p (http://localhost:8000/test.js:38:13)
at Anonymous function (http://localhost:8000/test.js:47:9)
at Global code (http://localhost:8000/test.js:42:1)
Nitro
func.name:
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name:
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name:
Trace:
i@http://localhost:8000/test.js:17:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: j
Trace:
j@http://localhost:8000/test.js:20:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: l
Trace:
l@http://localhost:8000/test.js:23:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name:
Trace:
http://localhost:8000/test.js:28:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: n
Trace:
n@http://localhost:8000/test.js:33:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
func.name: p
Trace:
p@http://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
#24
9
In JavaScript there are two ways to create functions:
在JavaScript中有两种创建函数的方法:
-
Function declaration:
函数声明:
function fn(){ console.log("Hello"); } fn();
This is very basic, self-explanatory, used in many languages and standard across C family of languages. We declared a function defined it and executed it by calling it.
这是非常基本的,不言自明的,用在许多语言和标准的C族语言中。我们声明一个函数定义它并通过调用它来执行它。
What you should be knowing is that functions are actually objects in JavaScript; internally we have created an object for above function and given it a name called fn or the reference to the object is stored in fn. Functions are objects in JavaScript; an instance of function is actually an object instance.
你应该知道函数实际上是JavaScript中的对象;在内部,我们为上面的函数创建了一个对象,并给它一个名为fn的名称,或者该对象的引用存储在fn中。函数是JavaScript中的对象;函数的实例实际上是一个对象实例。
-
Function expression:
函数表达式:
var fn=function(){ console.log("Hello"); } fn();
JavaScript has first-class functions, that is, create a function and assign it to a variable just like you create a string or number and assign it to a variable. Here, the fn variable is assigned to a function. The reason for this concept is functions are objects in JavaScript; fn is pointing to the object instance of the above function. We have initialized a function and assigned it to a variable. It's not executing the function and assigning the result.
JavaScript有一流的函数,即创建一个函数,并将其赋值给一个变量,就像你创建一个字符串或数字一样,并将其赋值给一个变量。这里,fn变量被分配给一个函数。这个概念的原因是函数是JavaScript中的对象;fn指向上述函数的对象实例。我们已经初始化了一个函数并将其赋值给一个变量。它没有执行函数并分配结果。
Reference: JavaScript function declaration syntax: var fn = function() {} vs function fn() {}
引用:JavaScript函数声明语法:var fn = function() {} vs函数fn() {}
#25
7
Both are different ways of defining a function. The difference is how the browser interprets and loads them into an execution context.
两者都是定义函数的不同方法。区别在于浏览器如何解释并将它们加载到执行上下文。
The first case is of function expressions which loads only when the interpreter reaches that line of code. So if you do it like the following, you will get an error that the functionOne is not a function.
第一个例子是函数表达式,只有当解释器到达这一行代码时才加载。如果你像下面这样做,你会得到一个错误,函数一不是函数。
functionOne();
var functionOne = function() {
// Some code
};
The reason is that on the first line no value is assigned to functionOne, and hence it is undefined. We are trying to call it as a function, and hence we are getting an error.
原因是在第一行中没有赋值给functionOne,因此它是未定义的。我们试着把它叫做函数,因此我们得到了一个错误。
On the second line we are assigning the reference of an anonymous function to functionOne.
在第二行中,我们将一个匿名函数的引用分配给functionOne。
The second case is of function declarations that loads before any code is executed. So if you do like the following you won't get any error as the declaration loads before code execution.
第二个例子是在执行任何代码之前加载的函数声明。因此,如果您这样做,您将不会在代码执行之前得到任何错误。
functionOne();
function functionOne() {
// Some code
}
#26
6
They are pretty similar with some small differences, first one is a variable which assigned to an anonymous function (Function Declaration) and second one is the normal way to create a function in JavaScript(Anonymous function Declaration), both has usage, cons and pros:
它们与一些细微的差别非常相似,第一个是分配给一个匿名函数(函数声明)的变量,第二个是在JavaScript中创建函数的正常方法(匿名函数声明),两者都有使用、反对和优点:
1. Function Expression
1。函数表达式
var functionOne = function() {
// Some code
};
A Function Expression defines a function as a part of a larger expression syntax (typically a variable assignment ). Functions defined via Functions Expressions can be named or anonymous. Function Expressions must not start with “function” (hence the parentheses around the self invoking example below).
函数表达式将函数定义为更大的表达式语法的一部分(通常是变量赋值)。通过函数表达式定义的函数可以命名或匿名。函数表达式不能以“函数”开头(因此,在下面的self调用示例中有一个圆括号)。
Assign a variable to a function, means no Hoisting, as we know functions in JavaScript can Hoist, means they can be called before they get declared, while variables need to be declared before getting access to them, so means in this case we can not access the function before where it's declared, also it could be a way that you write your functions, for the functions which return another function, this kind of declaration could make sense, also in ECMA6 & above you can assign this to an arrow function which can be used to call anonymous functions, also this way of declaring is a better way to create Constructor functions in JavaScript.
给变量分配一个函数,意味着没有提升,因为我们知道在JavaScript函数可以提升,意味着他们可以被称为之前宣布,而变量需要声明访问之前,在这种情况下,所以就意味着我们不能访问函数的声明之前,也可以是一种编写函数,函数返回另一个函数,这样的声明可以有意义,也在ECMA6 &上面你可以指定这个箭函数可用于调用匿名函数,这样的声明是一个更好的方法来创建JavaScript构造器函数。
2. Function Declaration
2。函数声明
function functionTwo() {
// Some code
}
A Function Declaration defines a named function variable without requiring variable assignment. Function Declarations occur as standalone constructs and cannot be nested within non-function blocks. It’s helpful to think of them as siblings of Variable Declarations. Just as Variable Declarations must start with “var”, Function Declarations must begin with “function”.
函数声明定义了一个命名函数变量,而不需要变量赋值。函数声明作为独立的结构出现,不能嵌套在非功能块中。把它们看作变量声明的兄弟姐妹是有帮助的。正如变量声明必须以“var”开头,函数声明必须以“函数”开始。
This is the normal way of calling a function in JavaScript, this function can be called before you even declare it as in JavaScript all functions get Hoisted, but if you have 'use strict' this won't Hoist as expected, it's a good way to call all normal functions which are not big in lines and neither are a constructor function.
这是正常的方式调用JavaScript函数,这个函数可以调用在你即使是在JavaScript函数声明它升起,但是如果你有使用严格的这不会提升正如预期的那样,这是一个好方法调用所有正常的功能并不大也行是一个构造函数。
Also, if you need more info about how hoisting works in JavaScript, visit the link below:
另外,如果您需要更多关于如何使用JavaScript进行提升的信息,请访问下面的链接:
https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
#27
6
About performance:
性能:
New versions of V8
introduced several under-the-hood optimizations and so did SpiderMonkey
.
V8的新版本引入了几个底层优化,SpiderMonkey也是如此。
There is almost no difference now between expression and declaration.
Function expression appears to be faster now.
表达式和声明之间几乎没有区别。函数表达式现在看起来更快了。
Chrome 62.0.3202
FireFox 55
Chrome金丝雀63.0.3225
Anonymous
function expressions appear to have better performance againstNamed
function expression.匿名函数表达式在命名函数表达式上似乎有更好的性能。
火狐浏览器Chrome金丝雀铬
#28
3
This is just two possible ways of declaring functions, and in the second way, you can use the function before declaration.
这仅仅是声明函数的两种方法,在第二种方法中,您可以在声明之前使用函数。
#29
3
new Function()
can be used to pass the function's body in a string. And hence this can be used to create dynamic functions. Also passing the script without executing the script.
可以使用new Function()将函数的主体传递给字符串。因此,这可以用来创建动态函数。还可以在不执行脚本的情况下传递脚本。
var func = new Function("x", "y", "return x*y;");
function secondFunction(){
var result;
result = func(10,20);
console.log ( result );
}
secondFunction()
#30
0
I prefer defining function as variable:
我喜欢将函数定义为变量:
let first = function(x){
return x[0];
}
Instead of:
而不是:
function first(){
....
}
Because i can use expressions and decorators when defining the function. For example:
因为我可以在定义函数时使用表达式和修饰符。例如:
let safe = function(f){
try {f()...}
}
let last = safe(function(x){return x[0]}).
Also with ES6 its much shorter:
也有ES6更短:
let last = x => x[0]
...........
function last(x){
return x[0];
}
......
let last = safe(x => x[0]);