您的位置:首页 > 其它

函数:声明和表达式

2016-02-26 22:08 232 查看
函数:声明和表达式

函数,像变量一样,可以在代码的任意地方定义它。
JS提供了几个方法去定义它们。
1.函数声明(FunctionDeclaration)
2.函数表达式(FunctionExpression)
3.通过调用newFunction返回。

语法
创建一个函数的基本方法是通过一个函数声明。语法如下:



function
f(arg1,arg2,...){
...code...
}


实现起来像这样子:

1
function
sayHi(name){
2
alert(
"Hi,"
+name)
3
}
4
5
sayHi(
'John'
)
上面的例子声明了一个带有一个参数name,函数名为sayHi的函数,并且调用了它。

返回值

我们用return语句来返回一个值。

1
function
sum(a,b){
2
return
a+b
3
}
4
5
var
result=sum(2,5)
6
alert(result)
如果函数不返回任何东西,它的结果会是一个特殊的值,undefined。你可以从下面的代码看到。

1
function
getNothing(){
2
//noreturn
3
}
4
5
var
result=getNothing()
6
7
alert(result)
一个空的返回也是一样:

1
function
getNothing(){
2
return
3
}
4
alert(getNothing()===undefined)
//true
局部变量

一个函数可以包括变量,通过var来定义。这些变量被称为局部变量,而且只能在函数内部使用。

1
function
sum(a,b){
2
var
sum=a+b
3
4
return
sum
5
}
函数声明

函数的声明的解析是在预执行(pre-execution)阶段,也就是浏览器准备执行代码的时候。

因此,通过函数声明来定义函数,可以在定义前或后被调用。

下面的代码是可以跑的:

1
function
sayHi(name){
2
alert(
"Hi,"
+name)
3
}
4
5
sayHi(
"John"
)
换个顺序也可以:

1
sayHi(
"John"
)
2
3
function
sayHi(name){
4
alert(
"Hi,"
+name)
5
}
一个函数可以在代码任意位置声明。

比如,我们可能要根据条件来声明不同的函数:



1
sayHi()
2
3
if
(1){
4
function
sayHi(){alert(1)}
5
}
else
{
6
function
sayHi(){alert(2)}
//<--
7
}
在写这篇文章的时候(作者本人没有给出他这这篇文章的时间——译者注),尝试在不同浏览器,火狐会抛出异常,其他两个浏览器都会给出结果2。

这是因为声明是在代码执行前解析的。根据规范(p.10.5),后面函数会覆盖前面存在的同名函数。

到了执行时期,声明会被忽略。所以if语句没有起作用。

函数表达式

在JS里面,函数function和number、string一样,是一阶值(原文为:first-classvalue,有人也译作:‘一等公民’)

只要可以放置变量的地方,都可以放置函数。在那个‘地方’用函数表达式的语法来声明:function(arguments){}

例如,你可以这样使用变量:
var
f=5

也可给f赋值一个函数表达式:

1
var
f=
function
(name){
2
alert(
"Hi,"
+name+
"!"
);
3
}
'function'关键字什么时候用作表达式,什么时候又用作声明
规则很简单

当js解析器看到function出现在主码流(maincodeflow不知如何翻译),function被认为是声明。

function
作为语句(statement)的一部分出现的,都会是表达式。

(译者认为,可以看能不能加分号来判断,能加分号的都为语句(statement)。)

函数表达式会在执行流(executionflow)执行到它的时候才会创建函数。所以,函数表达式必须被执行了(此时函数才定义了)才能被调用。

01
var
sayHi
02
03
//sayHi()<--can'tcallhere,thereisnosayHiyet
04
05
if
(1){
06
sayHi=
function
(){alert(1)}
07
}
else
{
08
sayHi=
function
(){alert(2)}
09
}
10
11
sayHi()
上面的例子,在所有浏览器执行的结果都一样。

请用函数声明

有经验的开发者,会将函数通过表达式来定义。

...code...
var
f=
function
(){...}
...
函数声明会更短更有可读性。

...code...
function
f(){...}
...
此外函数这样定义可以在定义前调用。

在你真正需要用函数表达式的使用它!特别是在有条件判断的时候定义函数。

函数是一个值

函数在JS里面是一个基本类型。我们甚至可以输出它:

1
function
f(){alert(1)}
2
3
alert(f)
上面的例子会输出这个function,通常是输出这个函数的源代码

无论是函数声明还是表达式,对函数来说,只是创建的时间不同而已。

传递一个函数

想所有值一样,不管是以哪种方式定义,函数可以被赋值,作为参数传递到另外的函数等等。

1
function
sayHi(name){
2
alert(
"Hi,"
+name)
3
}
4
5
var
hi=sayHi
//assignafunctiontoanothervariable
6
7
hi(
"dude"
)
//callthefunction
函数的传递是引用类型。也就是说,函数会存在内存的某个位置,sayhi是它的一个引用(如果你懂指针的话)。当把sayhi赋给hi的时候,两者都会引用到同一个函数。

函数可以接受另一个函数作为参数。

1
function
runWithOne(f){
//runsgivenfunctionwithargument1
2
f(1)
3
}
4
5
runWithOne(
6
function
(a){alert(a)}
7
)
逻辑上,函数是一个行为(action)。所以传递一个函数就是传递了一个可以被其他程序启动的行为。这个特性在js中广泛使用。

在上面的例子中,我们创建了一个没有名字的函数,而且没有把它赋给其他变量。这种函数被称为匿名函数。

就地运行

我们可以使用函数表达式创建一个函数并马上执行它。

1
(
function
(){
2
3
var
a,b
//localvariables
4
5
//...//andthecode
6
7
})()
我们涉及到局部变量的时候常用这种技巧。我们不想让局部变量污染到全局变量,所以我们把代码包在一个函数里面。

在代码执行后,全局变量还是干净的。这是一个最佳实践。

为什么函数被包在括号里面?这是因为js只能就地运行函数表达式。

函数声明不能像上面一样执行。

1
function
work(){
2
//...
3
}()
//syntaxerror
即使我们把名字去掉,JS还是会发现function这个关键字,把它解析成函数声明。

1
function
(){
//error,functiondeclarationwithoutname.
2
//...
3
}()
所以,只有把函数包在括号面才可行。然后解析器会认为它是语句中的一部分,把它提升为函数表达式。

如果函数明显就是一个表达式,那么也不用包起来。

1
var
result=
function
(a,b){
return
a+b}(2,2)
2
alert(result)
//4
上面的代码,函数会被创建并且马上执行。

下面代码的结果是啥?为啥?

1
var
a=5
2
3
(
function
(){
4
alert(a)
5
})()
P.S.想清楚哦童鞋,有陷阱哦~Ok,我已经提醒过你了。


Solution
答案是error.Tryit:



1
var
a=5
2
3
(
function
(){
4
alert(a)
5
})()
因为vara=5后面没有加分号,JS会这样处理的。

1
var
a=5(
function
(){
2
alert(a)
3
})()
所以,JS尝试把5当做函数来调用,这会导致错误。真正能用的代码如下。



1
var
a=5;
2
3
(
function
(){
4
alert(a)
5
})()
这应该是JS没有分号的最危险的陷阱了。

还有一种方法去定义还是就是直接调用Function构造器:



1
var
sayHi=
new
Function(
'name'
,
'alert("Hi,"+name)'
);
2
3
sayHi(
"Benedict"
);
它很少用,基本不用。

命名函数表达式

一个函数表达式可以有名字:

var
f=
function
sayHi(name){
alert(
"Hi,"
+name)
}
这个语法被称作命名函数表达式(namedfunctionexpressionorNFE),但是在IE<9下表现都不正常。
在支持这个语法的浏览器下,这个函数的名字只可以在函数内部被访问。

1
var
f=
function
sayHi(name){
2
alert(sayHi)
//outputsfunction
3
}
4
5
alert(sayHi)
//error:undefinedvariable'sayHi'
IE在这种情况下却创造了两个函数对象:sayHi和f

1
var
f=
function
g(){}
2
3
//falseinIE,error(gisundefined)inotherbrowsers
4
alert(f===g)
NFE存在的目的是让匿名函数可以递归。
看下面的包含在setTimeout里面的factorial函数:

setTimeout(
function
factorial(n){
return
n==1?n:n*factorial(n-1)
},100)
下面代码的结果是什么?为什么?

(
function
g(){
return
1})
alert(g)
Solution
答案是error:



1
(
function
g(){
return
1})
2
3
alert(g)
关键点是要理解
(function...)
是一个函数表达式而不是函数定义.

所以这是一个命名函数表达式。

命名表达式的名字只能在函数内部访问。

除了IE<9,其他浏览器都支持NFEs,所以它们会抛出‘undefinedvariable’异常,因为函数名
g
只能在内部被访问。

IE<9不支持NFE,所以它们会输出整个函数(源代码).

函数命名
函数是行为(action),所以应该起一个动词做名字,像get,red,calculateSum这些。
下面的情况是允许短函数名的:
1.函数在内嵌函数里面暂时使用的,和变量的逻辑一样。
2.函数会在整个代码里的多次被调用。一方面,你不会忘了它是干嘛用的,另一反面,你可以少些点代码。
现实世界中,像'$','$$','$A',这些,会经常在JS函数库里被使用。

其他情况下,还是应该用动词,或者动词做开头的函数名字

总结

函数在JS里面是基本类型。它们可以根据需要被赋值,传递和调用。
一个不返回任何东西的函数其实返回了undefined
用动词做函数名字。

FunctionDeclarationFunctionExpression
function在主代码流里面
function作为函数表达式的一部分
函数在代码执行前创建,可以在定义前被调用。当代码执行到的是创建,只能在定义后调用。
可以就地调用
转载:
http://www.cnblogs.com/Xdoable/archive/2011/09/08/2171512.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
章节导航