Ric*_*ide 6645 javascript syntax idioms function
我最近开始维护其他人的JavaScript代码.我正在修复错误,添加功能,并尝试整理代码并使其更加一致.
以前的开发人员使用两种声明函数的方法,如果背后有原因,我就无法解决.
这两种方式是:
var functionOne = function() {
// Some code
};
Run Code Online (Sandbox Code Playgroud)
function functionTwo() {
// Some code
}
Run Code Online (Sandbox Code Playgroud)
使用这两种不同方法的原因是什么?每种方法的优缺点是什么?有一种方法可以通过一种方法完成,而另一种方法无法完成吗?
Gre*_*reg 4907
不同之处在于它functionOne
是一个函数表达式,因此只在到达该行时定义,而是functionTwo
一个函数声明,并且只要执行其周围的函数或脚本(由于提升)就会定义.
例如,一个函数表达式:
// TypeError: functionOne is not a function
functionOne();
var functionOne = function() {
console.log("Hello!");
};
Run Code Online (Sandbox Code Playgroud)
并且,一个函数声明:
// Outputs: "Hello!"
functionTwo();
function functionTwo() {
console.log("Hello!");
}
Run Code Online (Sandbox Code Playgroud)
这也意味着您无法使用函数声明有条件地定义函数:
if (test) {
// Error or misbehavior
function functionThree() { doSomething(); }
}
Run Code Online (Sandbox Code Playgroud)
上面的实际定义functionThree
与... test
的值无关 - 除非use strict
有效,否则它只会引发错误.
Eug*_*kin 1906
首先,我想纠正Greg:function abc(){}
也是作用域 - 名称abc
是在遇到此定义的范围内定义的.例:
function xyz(){
function abc(){};
// abc is defined here...
}
// ...but not here
Run Code Online (Sandbox Code Playgroud)
其次,可以结合两种风格:
var xyz = function abc(){};
Run Code Online (Sandbox Code Playgroud)
xyz
将被定义为通常,abc
在所有浏览器中都是未定义的,但Internet Explorer - 不依赖于它的定义.但它将在其内部定义:
var xyz = function abc(){
// xyz is visible here
// abc is visible here
}
// xyz is visible here
// abc is undefined here
Run Code Online (Sandbox Code Playgroud)
如果要在所有浏览器上使用别名函数,请使用以下类型的声明:
function abc(){};
var xyz = abc;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,两个xyz
和abc
是同一个对象的别名:
console.log(xyz === abc); // prints "true"
Run Code Online (Sandbox Code Playgroud)
使用组合样式的一个令人信服的理由是函数对象的"名称"属性(Internet Explorer不支持).基本上当你定义一个函数时
function abc(){};
console.log(abc.name); // prints "abc"
Run Code Online (Sandbox Code Playgroud)
它的名称是自动分配的.但是当你定义它时
var abc = function(){};
console.log(abc.name); // prints ""
Run Code Online (Sandbox Code Playgroud)
它的名称是空的 - 我们创建了一个匿名函数并将其分配给某个变量.
使用组合样式的另一个好理由是使用简短的内部名称来引用自身,同时为外部用户提供长的非冲突名称:
// 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);
// ...
}
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,我们可以使用外部名称做同样的事情,但它太笨重(而且速度较慢).
(引用自身的另一种方法是使用arguments.callee
,它仍然相对较长,并且在严格模式下不受支持.)
在内心深处,JavaScript以不同的方式处理两种语句.这是一个函数声明:
function abc(){}
Run Code Online (Sandbox Code Playgroud)
abc
这里定义了当前范围内的所有位置:
// We can call it here
abc(); // Works
// Yet, it is defined down there.
function abc(){}
// We can call it again
abc(); // Works
Run Code Online (Sandbox Code Playgroud)
此外,它通过return
声明提出:
// We can call it here
abc(); // Works
return;
function abc(){}
Run Code Online (Sandbox Code Playgroud)
这是一个函数表达式:
var xyz = function(){};
Run Code Online (Sandbox Code Playgroud)
xyz
这里是从作业点定义的:
// We can't call it here
xyz(); // UNDEFINED!!!
// Now it is defined
xyz = function(){}
// We can call it here
xyz(); // works
Run Code Online (Sandbox Code Playgroud)
函数声明与函数表达式是Greg证明存在差异的真正原因.
有趣的事实:
var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"
Run Code Online (Sandbox Code Playgroud)
就个人而言,我更喜欢"函数表达式"声明,因为这样我可以控制可见性.当我定义函数时
var abc = function(){};
Run Code Online (Sandbox Code Playgroud)
我知道我在本地定义了这个函数.当我定义函数时
abc = function(){};
Run Code Online (Sandbox Code Playgroud)
我知道我在全球范围内定义它,只要我没有abc
在范围链中的任何地方定义.这种定义风格即使在内部使用也具有弹性eval()
.而定义
function abc(){};
Run Code Online (Sandbox Code Playgroud)
取决于上下文,可能会让你猜测它实际定义的位置,特别是在 - 的情况下eval()
- 答案是:它取决于浏览器.
T.J*_*der 609
这是创建函数的标准表单的纲要:( 最初是为另一个问题编写的,但在被移入规范问题后进行了调整.)
条款:
快速清单:
功能声明
"匿名" function
表达(尽管有术语,有时会创建带有名称的函数)
命名function
表达
存取器功能初始化器(ES5 +)
箭头函数表达式(ES2015 +)(与匿名函数表达式一样,不涉及显式名称,但可以创建带有名称的函数)
对象初始化器中的方法声明(ES2015 +)
class
(ES2015 +)中的构造函数和方法声明
第一种形式是函数声明,如下所示:
function x() {
console.log('x');
}
Run Code Online (Sandbox Code Playgroud)
函数声明是一个声明 ; 这不是一个陈述或表达.因此,你不要跟随它;
(尽管这样做是无害的).
在执行任何逐步执行代码之前,执行进入其出现的上下文时,将处理函数声明.它创建的函数具有正确的名称(x
在上面的示例中),并且该名称放在声明出现的范围内.
因为它是在同一个上下文中的任何分步代码之前处理的,所以你可以这样做:
x(); // Works even though it's above the declaration
function x() {
console.log('x');
}
Run Code Online (Sandbox Code Playgroud)
直到ES2015,该规范并没有涵盖,如果你把一个控制结构像内部函数声明中的JavaScript引擎应该做的事情try
,if
,switch
,while
,等等,是这样的:
if (someCondition) {
function foo() { // <===== HERE THERE
} // <===== BE DRAGONS
}
Run Code Online (Sandbox Code Playgroud)
而且由于它们是在逐步运行代码之前进行处理的,所以当它们处于控制结构中时知道该怎么做是很棘手的.
尽管在ES2015之前没有指定这样做,但它是一个允许的扩展来支持块中的函数声明.不幸的是(并且不可避免地),不同的引擎做了不同的事情.
从ES2015开始,规范说明了该怎么做.事实上,它提供了三个单独的事情:
松散模式的规则很棘手,但在严格模式下,块中的函数声明很容易:它们是块的本地(它们具有块范围,这在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)
Run Code Online (Sandbox Code Playgroud)
function
表达第二种常见形式称为匿名函数表达式:
var y = function () {
console.log('y');
};
Run Code Online (Sandbox Code Playgroud)
与所有表达式一样,它是在逐步执行代码时达到的.
在ES5中,它创建的函数没有名称(它是匿名的).在ES2015中,如果可能,通过从上下文推断该函数来为该函数指定名称.在上面的示例中,名称将是y
.当函数是属性初始值设定项的值时,会执行类似的操作.(有关何时发生这种情况的细节和规则,搜索SetFunctionName
在规范 -它似乎遍布的地方.)
function
表达第三种形式是命名函数表达式("NFE"):
var z = function w() {
console.log('zw')
};
Run Code Online (Sandbox Code Playgroud)
它创建的函数具有正确的名称(w
在本例中).与所有表达式一样,在逐步执行代码时,会对其进行评估.函数的名称未添加到表达式出现的范围中; 名称是在函数内部范围:
var z = function w() {
console.log(typeof w); // "function"
};
console.log(typeof w); // "undefined"
Run Code Online (Sandbox Code Playgroud)
请注意,NFE经常成为JavaScript实现的错误来源.例如,IE8及更早版本完全错误地处理NFE ,在两个不同的时间创建两个不同的函数.早期版本的Safari也存在问题.好消息是当前版本的浏览器(IE9及更高版本,当前的Safari)不再存在这些问题.(但在撰写本文时,遗憾的是,IE8仍然广泛使用,因此使用NFE和Web代码一般仍然存在问题.)
有时功能可以潜入大部分未被注意到; 这是访问者功能的情况.这是一个例子:
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"
Run Code Online (Sandbox Code Playgroud)
请注意,当我使用该功能时,我没有使用()
!那是因为它是一个属性的访问函数.我们以正常方式获取并设置属性,但在幕后,调用该函数.
您还可以使用Object.defineProperty
,Object.defineProperties
和不太知名的第二个参数创建访问器函数Object.create
.
ES2015为我们带来了箭头功能.这是一个例子:
var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6
Run Code Online (Sandbox Code Playgroud)
看到n => n * 2
隐藏在map()
通话中的东西?这是一个功能.
关于箭头功能的一些事情:
他们没有自己的this
.相反,他们关闭了在this
他们定义成背景.(它们也会关闭,arguments
并且在相关的地方super
.)这意味着它们this
内部与this
它们创建的位置相同,并且不能更改.
正如您已经注意到的那样,您不使用关键字function
; 相反,你使用=>
.
n => n * 2
上面的例子是它们的一种形式.如果您有多个参数来传递函数,则使用parens:
var a = [1, 2, 3];
var b = a.map((n, i) => n * i);
console.log(b.join(", ")); // 0, 2, 6
Run Code Online (Sandbox Code Playgroud)
(请记住,Array#map
将条目作为第一个参数传递,将索引作为第二个参数传递.)
在这两种情况下,函数的主体只是一个表达式; 函数的返回值将自动成为该表达式的结果(您不使用显式return
).
如果你做的不仅仅是单个表达式,请使用{}
和显式return
(如果你需要返回一个值),正常情况下:
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));
Run Code Online (Sandbox Code Playgroud)
没有的版本{ ... }
被称为带有表达体或简洁体的箭头函数.(另外:一个简洁的箭头功能.){ ... }
定义主体的那个是带有功能体的箭头功能.(另外:一个冗长的箭头功能.)
ES2015允许更短的形式声明一个引用称为方法定义的函数的属性; 它看起来像这样:
var o = {
foo() {
}
};
Run Code Online (Sandbox Code Playgroud)
在ES5和之前的几乎相当于:
var o = {
foo: function foo() {
}
};
Run Code Online (Sandbox Code Playgroud)
差异(除了详细程度)是一个方法可以使用super
,但一个功能不能.因此,举例来说,如果你有一个valueOf
使用方法语法定义(比方说)的对象,它可以super.valueOf()
用来获取Object.prototype.valueOf
返回的值(之前可能用它做其他事情),而ES5版本则必须这样做Object.prototype.valueOf.call(this)
.
这也意味着该方法引用了它所定义的对象,因此如果该对象是临时的(例如,您将其Object.assign
作为源对象之一传递),则方法语法可能意味着该对象被保留在内存中,否则它可能被垃圾收集(如果JavaScript引擎没有检测到这种情况,并处理它,如果没有方法使用super
).
class
(ES2015 +)中的构造函数和方法声明ES2015为我们带来了class
语法,包括声明的构造函数和方法:
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName() {
return this.firstName + " " + this.lastName;
}
}
Run Code Online (Sandbox Code Playgroud)
上面有两个函数声明:一个用于构造函数,一个用于获取名称Person
,另一个用于for getFullName
,它是一个分配给的函数Person.prototype
.
CMS*_*CMS 139
说到全局上下文,var
语句和FunctionDeclaration
最后都将在全局对象上创建一个不可删除的属性,但两者的值都可以被覆盖.
两种方式之间的细微差别在于,当变量实例化过程运行时(在实际代码执行之前),所有声明的标识符var
都将被初始化undefined
,并且FunctionDeclaration
自那时起使用的标识符将可用,例如:
alert(typeof foo); // 'function', it's already available
alert(typeof bar); // 'undefined'
function foo () {}
var bar = function () {};
alert(typeof bar); // 'function'
Run Code Online (Sandbox Code Playgroud)
分配bar
FunctionExpression
发生在运行时间.
由a创建的全局属性FunctionDeclaration
可以像变量值一样被覆盖而没有任何问题,例如:
function test () {}
test = null;
Run Code Online (Sandbox Code Playgroud)
您的两个示例之间的另一个明显区别是第一个函数没有名称,但第二个函数有它,这在调试(即检查调用堆栈)时非常有用.
关于您编辑的第一个示例(foo = function() { alert('hello!'); };
),这是一个未声明的作业,我强烈建议您始终使用该var
关键字.
使用赋值,如果没有var
语句,如果在作用域链中找不到引用的标识符,它将成为全局对象的可删除属性.
此外,未声明的作业ReferenceError
在严格模式下投入ECMAScript 5 .
必读:
注意:这个答案已经与另一个问题合并,其中OP的主要疑问和误解是用a声明的标识符FunctionDeclaration
不能被覆盖,但事实并非如此.
tho*_*ter 121
您在那里发布的两个代码片段几乎在所有目的下都会以相同的方式运行.
但是,行为的差异在于使用第一个variant(var functionOne = function() {}
),该函数只能在代码中的该点之后调用.
使用第二个variant(function functionTwo()
),该函数可用于在声明函数的上方运行的代码.
这是因为对于第一个变体,函数foo
在运行时分配给变量.在第二个中,foo
在解析时将该函数分配给该标识符.
更多技术信息
JavaScript有三种定义函数的方法.
eval()
存在问题的方式相同.suh*_*lvs 100
更好地解释格雷格的答案
functionTwo();
function functionTwo() {
}
Run Code Online (Sandbox Code Playgroud)
为什么没有错误?我们总是被告知表达式是从上到下执行的(??)
函数声明和变量声明总是
hoisted
被JavaScript解释器无形地移动到其包含范围的顶部.显然,功能参数和语言定义的名称已经存在.本樱桃
这意味着代码如下:
functionOne(); --------------- var functionOne;
| is actually | functionOne();
var functionOne = function(){ | interpreted |-->
}; | like | functionOne = function(){
--------------- };
Run Code Online (Sandbox Code Playgroud)
请注意,声明的赋值部分未被提升.只有名字被悬挂.
但在函数声明的情况下,整个函数体也将被提升:
functionTwo(); --------------- function functionTwo() {
| is actually | };
function functionTwo() { | interpreted |-->
} | like | functionTwo();
---------------
Run Code Online (Sandbox Code Playgroud)
Sea*_*lan 89
其他评论者已经涵盖了上述两种变体的语义差异.我想要注意一个风格差异:只有"赋值"变体可以设置另一个对象的属性.
我经常用这样的模式构建JavaScript模块:
(function(){
var exports = {};
function privateUtil() {
...
}
exports.publicUtil = function() {
...
};
return exports;
})();
Run Code Online (Sandbox Code Playgroud)
使用此模式,您的公共函数将全部使用赋值,而您的私有函数使用声明.
(另请注意,赋值在语句后应该使用分号,而声明禁止它.)
Mbe*_*ane 76
何时优先考虑第一种方法到第二种方法的说明是当你需要避免覆盖函数的先前定义时.
同
if (condition){
function myfunction(){
// Some code
}
}
Run Code Online (Sandbox Code Playgroud)
,这个定义myfunction
将覆盖任何先前的定义,因为它将在分析时完成.
而
if (condition){
var myfunction = function (){
// Some code
}
}
Run Code Online (Sandbox Code Playgroud)
myfunction
只有在condition
满足时才能正确定义.
Rob*_*Rob 61
一个重要的原因是添加一个且只有一个变量作为命名空间的"根"...
var MyNamespace = {}
MyNamespace.foo= function() {
}
Run Code Online (Sandbox Code Playgroud)
要么
var MyNamespace = {
foo: function() {
},
...
}
Run Code Online (Sandbox Code Playgroud)
命名空间有很多技巧.随着大量JavaScript模块的出现,它变得越来越重要.
Yas*_*ash 55
提升 是JavaScript解释器将所有变量和函数声明移动到当前范围顶部的操作.
但是,只有实际的声明才会被提升.将任务留在原处.
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.
};
Run Code Online (Sandbox Code Playgroud)
功能
function Identifier_opt ( FormalParameterList_opt ) {
FunctionBody | sequence of statements
« return; Default undefined
« return 'some data';
}
Run Code Online (Sandbox Code Playgroud)
函数的默认返回值是' undefined ',变量声明默认值也是'undefined'
Scope with respect to function-block global.
Scope with respect to page undefined | not available.
Run Code Online (Sandbox Code Playgroud)功能声明
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
Run Code Online (Sandbox Code Playgroud)
功能表达
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'
};
Run Code Online (Sandbox Code Playgroud)
分配给变量的函数示例:
(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();
Run Code Online (Sandbox Code Playgroud)
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();
Run Code Online (Sandbox Code Playgroud)
您可以使用查看不同浏览器的函数声明,表达式测试 jsperf Test Runner
ES5构造函数类:使用Function.prototype.bind创建的函数对象
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
Run Code Online (Sandbox Code Playgroud)
ES6引入了箭头函数:箭头函数表达式具有较短的语法,它们最适合非方法函数,并且它们不能用作构造函数.
ArrowFunction : ArrowParameters => ConciseBody
.Run Code Online (Sandbox Code Playgroud)const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; }; console.log( fn(2) ); // Even console.log( fn(3) ); // Odd
Leo*_*ban 40
我正在添加我自己的答案,因为其他人都彻底覆盖了吊装部件.
我想知道现在哪种方式更好,现在感谢http://jsperf.com我知道:)
函数声明更快,这对于web开发中真正重要的是什么?;)
elj*_*nso 33
一旦建立绑定,分配给变量的函数声明和函数表达式的行为相同.
然而,函数对象与其变量实际关联的方式和时间存在差异.这种差异是由于JavaScript中的变量提升机制造成的.
基本上,所有函数声明和变量声明都被提升到声明发生的函数的顶部(这就是为什么我们说JavaScript具有函数作用域).
当函数声明被提升时,函数体"跟随",因此当评估函数体时,变量将立即绑定到函数对象.
当一个变量声明悬挂,初始化并没有
跟随,而是"留下".变量初始化为
undefined
函数体的开头,并
在代码中的原始位置分配一个值.(实际上,它将在每个发生具有相同名称的变量声明的位置分配一个值.)
提升的顺序也很重要:函数声明优先于具有相同名称的变量声明,最后一个函数声明优先于具有相同名称的先前函数声明.
一些例子...
var foo = 1;
function bar() {
if (!foo) {
var foo = 10 }
return foo; }
bar() // 10
Run Code Online (Sandbox Code Playgroud)
变量foo
被提升到的功能,初始化的顶部undefined
,从而使!foo
是true
,所以foo
被分配10
.范围的foo
外部bar
没有任何作用,也没有受到影响.
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
Run Code Online (Sandbox Code Playgroud)
函数声明优先于变量声明,最后一个函数声明"粘".
function f() {
var a = 4;
function a() {return 1};
function a() {return 2};
return a; }
f() // 4
Run Code Online (Sandbox Code Playgroud)
在此示例a
中,使用通过计算第二个函数声明得到的函数对象进行初始化,然后进行分配4
.
var a = 1;
function b() {
a = 10;
return;
function a() {}}
b();
a // 1
Run Code Online (Sandbox Code Playgroud)
这里首先提升函数声明,声明并初始化变量a
.接下来,分配此变量10
.换句话说:赋值不分配给外部变量a
.
sla*_*5er 32
第一个例子是函数声明:
function abc(){}
Run Code Online (Sandbox Code Playgroud)
第二个例子是函数表达式:
var abc = function() {};
Run Code Online (Sandbox Code Playgroud)
主要区别在于如何吊起(举起和宣布).在第一个示例中,整个函数声明被提升.在第二个例子中,只有var'abc'被提升,它的值(函数)将是未定义的,并且函数本身保持在声明它的位置.
简而言之:
//this will work
abc(param);
function abc(){}
//this would fail
abc(param);
var abc = function() {}
Run Code Online (Sandbox Code Playgroud)
要了解有关此主题的更多信息,我强烈建议您使用此 链接
Sas*_*sov 29
在代码维护成本方面,命名函数更为可取:
我怀疑命名函数的PROS会更多.被列为命名函数优势的是匿名函数的缺点.
从历史上看,匿名函数出现在JavaScript无法作为列出具有命名函数的成员的语言中:
{
member:function() { /* How do I make "this.member" a named function? */
}
}
Run Code Online (Sandbox Code Playgroud)
Her*_*erc 25
我在代码中使用变量方法是出于一个非常具体的原因,其理论已在上面以一种抽象的方式介绍,但是一个例子可能会帮助像我这样的人,JavaScript专业知识有限.
我有代码需要运行160个独立设计的品牌.大多数代码都在共享文件中,但品牌特定的东西在一个单独的文件中,每个品牌一个.
有些品牌需要特定功能,有些则不需要.有时我必须添加新功能来执行新的品牌特定事物.我很乐意更改共享编码,但我不想更改所有160套品牌文件.
通过使用变量语法,我可以在共享代码中声明变量(本质上是一个函数指针),并分配一个普通的存根函数,或设置为null.
然后,需要特定功能实现的一个或两个品牌可以定义它们的函数版本,并在需要时将其分配给变量,其余的则不执行任何操作.我可以在共享代码中执行之前测试null函数.
根据上面人们的评论,我认为也可以重新定义静态函数,但我认为变量解决方案很好而且清晰.
小智 24
在计算机科学术语中,我们讨论匿名函数和命名函数.我认为最重要的区别是匿名函数没有绑定到名称,因此名称是匿名函数.在JavaScript中,它是在运行时动态声明的第一个类对象.
有关匿名函数和lambda演算的更多信息,维基百科是一个良好的开端(http://en.wikipedia.org/wiki/Anonymous_function).
Roh*_*han 22
格雷格的答案已经足够好了,但我还是想补充一点,我刚才看到道格拉斯·克罗克福德的视频.
功能表达:
var foo = function foo() {};
Run Code Online (Sandbox Code Playgroud)
功能说明:
function foo() {};
Run Code Online (Sandbox Code Playgroud)
函数语句只是var
带有function
值的语句的简写.
所以
function foo() {};
Run Code Online (Sandbox Code Playgroud)
扩展到
var foo = function foo() {};
Run Code Online (Sandbox Code Playgroud)
其进一步扩展到:
var foo = undefined;
foo = function foo() {};
Run Code Online (Sandbox Code Playgroud)
它们都被提升到代码的顶部.
Joe*_*rra 18
@EugeneLazutkin给出了一个例子,他将一个指定的函数命名为能够shortcut()
用作自身的内部引用.John Resig给出了另一个例子 - 在他的Learning Advanced Javascript教程中复制分配给另一个对象的递归函数.虽然向属性分配函数并不是严格意义上的问题,但我建议您主动尝试教程 - 通过单击右上角的按钮运行代码,然后双击代码以根据自己的喜好进行编辑.
本教程中的示例:递归调用yell()
:
删除原始ninja对象时测试失败.(第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?" );
}
Run Code Online (Sandbox Code Playgroud)
如果命名将以递归方式调用的函数,则测试将通过.(第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." );
Run Code Online (Sandbox Code Playgroud)
Ing*_*gel 16
其他答案中没有提到的另一个区别是,如果您使用匿名函数
var functionOne = function() {
// Some code
};
Run Code Online (Sandbox Code Playgroud)
并将其用作构造函数
var one = new functionOne();
Run Code Online (Sandbox Code Playgroud)
然后one.constructor.name
将不会被定义.Function.name
是非标准的,但得到Firefox,Chrome,其他Webkit派生的浏览器和IE 9+的支持.
同
function functionTwo() {
// Some code
}
two = new functionTwo();
Run Code Online (Sandbox Code Playgroud)
可以将构造函数的名称作为字符串检索two.constructor.name
.
Nul*_*teя 14
第一个(函数doSomething(x))应该是对象表示法的一部分.
第二个(var doSomething = function(x){ alert(x);}
)只是创建一个匿名函数并将其赋值给变量doSomething
.所以doSomething()将调用该函数.
您可能想知道函数声明和函数表达式是什么.
函数声明定义了一个命名函数变量,而不需要变量赋值.函数声明作为独立构造出现,不能嵌套在非函数块中.
function foo() {
return 3;
}
Run Code Online (Sandbox Code Playgroud)
ECMA 5(13.0)将语法定义为
函数Identifier(FormalParameterList opt){FunctionBody}
在上述条件中,函数名称在其范围内以及其父级的范围内可见(否则它将无法访问).
并在函数表达式中
函数表达式将函数定义为较大表达式语法(通常是变量赋值)的一部分.通过函数表达式定义的函数可以是命名的或匿名的.函数表达式不应以"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!");
})();
Run Code Online (Sandbox Code Playgroud)
ECMA 5(13.0)将语法定义为
函数Identifier opt(FormalParameterList opt){FunctionBody}
Paw*_*iak 14
如果您将使用这些函数来创建对象,您将获得:
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
Run Code Online (Sandbox Code Playgroud)
小智 14
我列出了以下差异:
函数声明可以放在代码中的任何位置.即使在定义出现在代码之前调用它,它也会在函数声明被提交到内存或以某种方式被提升之前执行,之后页面中的任何其他代码开始执行.
看看下面的功能:
function outerFunction() {
function foo() {
return 1;
}
return foo();
function foo() {
return 2;
}
}
alert(outerFunction()); // Displays 2
Run Code Online (Sandbox Code Playgroud)
这是因为,在执行期间,它看起来像: -
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
Run Code Online (Sandbox Code Playgroud)
函数表达式(如果在调用之前未定义)将导致错误.此外,这里函数定义本身不会像函数声明一样移动到顶部或提交到内存.但是我们分配函数的变量被提升并且未定义被分配给它.
使用函数表达式的相同函数
function outerFunction() {
var foo = function() {
return 1;
}
return foo();
var foo = function() {
return 2;
}
}
alert(outerFunction()); // Displays 1
Run Code Online (Sandbox Code Playgroud)
这是因为在执行期间,它看起来像:
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
Run Code Online (Sandbox Code Playgroud)它是不是安全写在非功能块函数声明一样,如果因为他们将无法访问.
if (test) {
function x() { doSomething(); }
}
Run Code Online (Sandbox Code Playgroud)如下所示的命名函数表达式可能无法在版本9之前的Internet Explorer浏览器中使用.
var today = function today() {return new Date()}
Run Code Online (Sandbox Code Playgroud)Jac*_*fin 12
下面列出的两种不同功能声明之间有四个值得注意的比较.
以下工作原因因为function add()
范围限定为最近的块:
try {
console.log("Success: ", add(1, 1));
} catch(e) {
console.log("ERROR: " + e);
}
function add(a, b){
return a + b;
}
Run Code Online (Sandbox Code Playgroud)
以下不起作用(因为add
取代了add = undefined
).
try {
console.log("Success: ", add(1, 1));
} catch(e) {
console.log("ERROR: " + e);
}
var add=function(a, b){
return a + b;
}
Run Code Online (Sandbox Code Playgroud)
以下内容不起作用,因为var add;
在使用后声明.
var add = undefined;
try {
console.log("Success: ", add(1, 1));
} catch(e) {
console.log("ERROR: " + e);
}
add = function(a, b){
return a + b;
}
Run Code Online (Sandbox Code Playgroud)
一个函数的名称var add=undefined
是thefuncname当它这样声明.
try {
console.log("Success: ", add(1, 1));
} catch(e) {
console.log("ERROR: " + e);
}
var add=function add(a, b){
return a + b;
}
Run Code Online (Sandbox Code Playgroud)
function foobar(a, b){}
console.log(foobar.name);
Run Code Online (Sandbox Code Playgroud)
否则,如果函数声明为var add=
,则函数 .name是用于存储函数的第一个变量.
var a = function foobar(){};
console.log(a.name);
Run Code Online (Sandbox Code Playgroud)
如果没有为函数设置变量,则函数名称为空字符串(function add()
).
var a = function(){};
var b = (function(){ return function(){} });
console.log(a.name);
console.log(b.name);
Run Code Online (Sandbox Code Playgroud)
最后,虽然为函数分配的变量最初设置名称,但设置为函数的连续变量不会更改名称.
console.log((function(){}).name === "");
Run Code Online (Sandbox Code Playgroud)
在Google的V8和Firefox的Spidermonkey中,可能存在几微秒的JIST编译差异,但最终结果完全相同.为了证明这一点,让我们通过比较两个空白代码片段的速度来检查JSPerf在微基准测试中的效率.该JSPerf测试是在这里找到.并且,这里发现了jsben.ch测试.正如你所看到的,当应该没有时,会有明显的区别.如果你真的像我这样的表现怪物,那么在尝试减少范围中的变量和函数的数量时尤其是消除多态性(例如使用相同的变量来存储两种不同的类型)可能更值得.
当您使用function thefuncname(){}
关键字声明变量时,您可以将其他值重新分配给变量.
var a = function(){};
var b = a;
var c = b;
console.log(a.name);
console.log(b.name);
console.log(c.name);
Run Code Online (Sandbox Code Playgroud)
但是,当我们使用const语句时,变量引用变为不可变.这意味着我们无法为变量分配新值.但请注意,这并不会使变量的内容成为不可变的:如果你这样做function(){}
,那么你仍然可以""
.只做类似var
或const arr = []
会抛出错误,如下所示.
(function(){
"use strict";
var foobar = function(){}; // initial value
try {
foobar = "Hello World!"; // new value
console.log("[no error]");
} catch(error) {
console.log("ERROR: " + error.message);
}
console.log(foobar, window.foobar);
})();
Run Code Online (Sandbox Code Playgroud)
有趣的是,如果我们将变量声明为arr[10] = "example"
,那么变量的不变性与声明它一样arr = "new value"
.
(function(){
"use strict";
const foobar = function(){}; // initial value
try {
foobar = "Hello World!"; // new value
console.log("[no error]");
} catch(error) {
console.log("ERROR: " + error.message);
}
console.log(foobar, window.foobar);
})();
Run Code Online (Sandbox Code Playgroud)
"最近的块"是最近的"函数"(包括异步函数,生成器函数和异步生成器函数).然而,有趣的arr = []
是function funcName(){}
,在非闭包块中的行为类似于闭包之外的物品.观察.
var
(function(){
"use strict";
function foobar(){}; // initial value
try {
foobar = "Hello World!"; // new value
console.log("[no error]");
} catch(error) {
console.log("ERROR: " + error.message);
}
console.log(foobar, window.foobar);
})();
Run Code Online (Sandbox Code Playgroud)
function functionName() {}
try {
// typeof will simply return "undefined" if the variable does not exist
if (typeof add !== "undefined") {
add(1, 1); // just to prove it
console.log("Not a block");
}else if(add===undefined){ // this throws an exception if add doesn't exist
console.log('Behaves like var add=function(a,b){return a+b}');
}
} catch(e) {
console.log("Is a block");
}
var add=function(a, b){return a + b}
Run Code Online (Sandbox Code Playgroud)
try {
// typeof will simply return "undefined" if the variable does not exist
if (typeof add !== "undefined") {
add(1, 1); // just to prove it
console.log("Not a block");
}else if(add===undefined){ // this throws an exception if add doesn't exist
console.log('Behaves like var add=function(a,b){return a+b}')
}
} catch(e) {
console.log("Is a block");
}
function add(a, b){
return a + b;
}
Run Code Online (Sandbox Code Playgroud)
var functionName = function() {}
,var add=function(){}
,function add(){}
,if
,else
/ for
/ while
,try
,catch
/ finally
,switch
)try {
// typeof will simply return "undefined" if the variable does not exist
if (typeof add !== "undefined") {
add(1, 1); // just to prove it
console.log("Not a block");
}else if(add===undefined){ // this throws an exception if add doesn't exist
console.log('Behaves like var add=function(a,b){return a+b}')
}
} catch(e) {
console.log("Is a block");
}
(function () {
function add(a, b){
return a + b;
}
})();
Run Code Online (Sandbox Code Playgroud)
do
try {
// typeof will simply return "undefined" if the variable does not exist
if (typeof add !== "undefined") {
add(1, 1); // just to prove it
console.log("Not a block");
}else if(add===undefined){ // this throws an exception if add doesn't exist
console.log('Behaves like var add=function(a,b){return a+b}')
}
} catch(e) {
console.log("Is a block");
}
{
function add(a, b){
return a + b;
}
}
Run Code Online (Sandbox Code Playgroud)
while
try {
// typeof will simply return "undefined" if the variable does not exist
if (typeof add !== "undefined") {
add(1, 1); // just to prove it
console.log("Not a block");
}else if(add===undefined){ // this throws an exception if add doesn't exist
console.log('Behaves like var add=function(a,b){return a+b}')
}
} catch(e) {
console.log("Is a block");
}
(() => {
var add=function(a, b){
return a + b;
}
})();
Run Code Online (Sandbox Code Playgroud)
Jac*_*son 11
鉴于"命名函数显示在堆栈跟踪"参数,现代JavaScript引擎实际上非常能够表示匿名函数.
在撰写本文时,V8,SpiderMonkey,Chakra和Nitro总是通过他们的名字来引用命名函数.它们几乎总是通过标识符引用匿名函数(如果有的话).
SpiderMonkey可以找出从另一个函数返回的匿名函数的名称.其余的不能.
如果你真的,真的希望你的迭代器和成功回调显示在跟踪中,你可以命名那些......
[].forEach(function iterator() {});
Run Code Online (Sandbox Code Playgroud)
但在大多数情况下,不值得强调.
'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'));
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
Ano*_*Rai 10
在JavaScript中,有两种方法可以创建函数:
功能声明:
function fn(){
console.log("Hello");
}
fn();
Run Code Online (Sandbox Code Playgroud)
这是非常基本的,不言自明的,在C语言系列中以多种语言和标准使用.我们声明了一个函数定义它并通过调用它来执行它.
您应该知道的是,函数实际上是JavaScript中的对象; 在内部,我们为上面的函数创建了一个对象,并给它一个名为fn的名称,或者对象的引用存储在fn中.函数是JavaScript中的对象; 函数实例实际上是一个对象实例.
功能表达:
var fn=function(){
console.log("Hello");
}
fn();
Run Code Online (Sandbox Code Playgroud)
JavaScript具有一流的功能,即创建一个函数并将其分配给变量,就像创建字符串或数字并将其分配给变量一样.这里,fn变量被赋值给一个函数.这个概念的原因是函数是JavaScript中的对象; fn指向上述函数的对象实例.我们初始化了一个函数并将其分配给变量.它没有执行该功能并分配结果.
参考:JavaScript函数声明语法:var fn = function(){} vs function fn(){}
两者都是定义函数的不同方式.不同之处在于浏览器如何解释并将它们加载到执行上下文中.
第一种情况是函数表达式,仅在解释器到达该行代码时才加载.因此,如果您执行以下操作,您将收到一个错误,即functionOne不是函数.
functionOne();
var functionOne = function() {
// Some code
};
Run Code Online (Sandbox Code Playgroud)
原因是在第一行没有为functionOne赋值,因此它是未定义的.我们试图将其称为函数,因此我们得到一个错误.
在第二行,我们将一个匿名函数的引用分配给functionOne.
第二种情况是在执行任何代码之前加载的函数声明.因此,如果您喜欢以下内容,则在代码执行之前加载声明时不会出现任何错误.
functionOne();
function functionOne() {
// Some code
}
Run Code Online (Sandbox Code Playgroud)
它们非常相似,只有一些小差异,第一个是分配给匿名函数的变量(函数声明),第二个是在JavaScript中创建函数的常规方法(匿名函数声明),两者都有用法,缺点和优点:
1.功能表达
var functionOne = function() {
// Some code
};
Run Code Online (Sandbox Code Playgroud)
函数表达式将函数定义为更大表达式语法(通常是变量赋值)的一部分.通过函数表达式定义的函数可以命名或匿名.函数表达式不能以"function"开头(因此下面是自调用示例的括号).
将一个变量分配给一个函数,意味着没有提升,因为我们知道JavaScript中的函数可以提升,意味着它们可以在声明之前被调用,而变量需要在获取它们之前声明,所以在这种情况下意味着我们不能在声明它之前访问函数,也可以是你编写函数的一种方式,对于返回另一个函数的函数,这种声明是有意义的,同样在ECMA6及以上你可以将它赋给箭头函数可以用来调用匿名函数,这种声明方式也是在JavaScript中创建构造函数的更好方法.
2.功能声明
function functionTwo() {
// Some code
}
Run Code Online (Sandbox Code Playgroud)
函数声明定义了一个命名函数变量,无需变量赋值.函数声明作为独立构造出现,不能嵌套在非函数块中.将它们视为变量声明的兄弟是有帮助的.正如变量声明必须以"var"开头一样,函数声明必须以"function"开头.
这是在JavaScript中调用函数的常规方法,这个函数可以在你将它声明之前调用,因为在JavaScript中所有函数都被提升,但如果你有'使用严格',这将不会像预期的那样提升,这是一个好方法调用行中不大的所有普通函数,它们都不是构造函数.
此外,如果您需要有关如何在JavaScript中提升的更多信息,请访问以下链接:
https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
这称为函数表达式:
var getRectArea = function(width, height) {
return width * height;
};
console.log("Area of Rectangle: " + getRectArea(3,4));
// This should return the following result in the console:
// Area of Rectangle: 12
Run Code Online (Sandbox Code Playgroud)
这称为函数声明:
var w = 5;
var h = 6;
function RectArea(width, height) { //declaring the function
return area = width * height;
} //note you do not need ; after }
RectArea(w,h); //calling or executing the function
console.log("Area of Rectangle: " + area);
// This should return the following result in the console:
// Area of Rectangle: 30
Run Code Online (Sandbox Code Playgroud)
希望这有助于解释函数表达式和函数声明之间的区别以及如何使用它们。谢谢。
new Function()
可用于在字符串中传递函数的主体。因此,可以将其用于创建动态功能。也传递脚本而不执行脚本。
var func = new Function("x", "y", "return x*y;");
function secondFunction(){
var result;
result = func(10,20);
console.log ( result );
}
secondFunction()
Run Code Online (Sandbox Code Playgroud)
第一个是匿名函数表达式:
var functionOne = function() {
// some code
};
Run Code Online (Sandbox Code Playgroud)
而第二个是函数声明:
function functionTwo () {
// some code
}
Run Code Online (Sandbox Code Playgroud)
两者之间的主要明显区别在于函数名称,因为匿名函数没有可调用的名称。
匿名函数快速且易于键入,许多库和工具倾向于鼓励这种惯用的代码风格。但是,匿名函数有一些缺点:
可读性:匿名函数省略了可能导致代码可读性降低的名称。
调试:匿名函数在堆栈跟踪中没有名称,这会使调试更加困难。
自引用:如果函数需要引用自身,例如递归。
命名函数表达式:
为您的函数表达式提供一个名称非常有效地解决了所有这些缺点,并且没有明显的缺点。最佳做法是始终命名您的函数表达式:
setTimeout(function timeHandler() { // <-- look, a name here!
console.log("I've waited 1 second");
}, 1000);
Run Code Online (Sandbox Code Playgroud)
命名 IIFE(立即调用函数表达式):
(function IIFE(str) { // <-- look, always name IIFEs!
console.log(str); // "Hello!"
})('Hello!');
Run Code Online (Sandbox Code Playgroud)
对于分配给变量的函数,命名函数,在这种情况下,不是很常见,可能会引起混淆,在这种情况下,箭头函数可能是更好的选择。