函数是Function类型的实例,所以函数也是对象,从而函数也拥有方法,可用来增强其行为。(这一点正是JS最有特色的地方)
函数名实际上是一个指向函数对象的指针,不会与某个函数绑定。
一、函数的定义
-
函数声明语法:
function sum(num1, num2){
return num1 + num2;
}//使用不带圆括号的函数名是访问函数指针,并非调用函数;
-
函数表达式:
var sum = function(num1, num2){
return num1 + num2;
};//注意:函数末尾有分号,就像声明其它变量一样;通过变量sum即可调用函数;
-
Function构造函数:
var sum = new Function("num1" , "num2" , " return num1 + num2");//不推荐;前面是参数,最后是函数体;
当声明了多个同名函数时,后面的函数覆盖前面的函数,没有重载发生,主要是因为ECMAScript没有函数签名。
区分函数声明和函数表达式:解析器优先读取函数声明,并使其在执行任何代码之前可用(可访问);函数表达式,必须等到解析器执行到它所在的代码行才被执行,除了什么时候可以通过变量访问函数这点区别外,二者没有区别。当使用函数声明的形式来定义函数时,可将调用语句写在函数声明之前,而后者,这样做的话会报错。
函数名本身即为变量,所以函数可以作为值来使用,可将一个函数作为参数传递给另一个函数(函数作为参数时后面不可加括号),也可将一个函数作为另一个函数的返回值。
二、函数内部属性
函数内部有两个特殊对象:arguments和this。
-
arguments是一个类数组对象,包含着传入函数中的所有参数。该对象有一个名为callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。
function factorial(num){//阶乘函数
if(num <=1){
return 1;
}else {
return num * arguments.callee(num-1);//这样将函数的执行与函数名解耦合;
}
}
-
this,引用的是函数据以执行的环境对象。
window.color = "red";
var o = { color: "blue" };
function sayColor(){
alert(this.color);
}
sayColor(); //red
o.sayColor = sayColor;
o.sayColor(); //blue
-
ECMAScript5规范了另一个函数对象的属性:caller,该属性中保存着调用当前函数的函数引用,如果是在全局作用域中调用当前函数,该值为null。
function outer(){
inner();
}
function inner(){
alert(arguments.callee.caller);
}
outer();//最后显示outer()函数的源代码,但要注意,不能为函数的caller属性赋值,否则导致错误
三、函数属性和方法
函数是对象,因此也具有属性和方法,每个函数都包含两个属性:length和prototype。
-
length属性表示函数希望接收的命名参数的个数;
-
prototype属性时保存所有实例方法,该属性不可枚举,因此无法用for-in实现;诸如toString()、valueOf()等方法均保存在prototype名下,只不过是通过各自对象的实例访问;
每个函数还包括两个非继承而来的方法:apply()、call()。
-
二者的用途都是在特定作用域中调用函数,实际上等于设置函数体内的this对象值;
-
apply()接收两个参数:在其中运行函数的作用域,另一个是参数数组;
-
call()接收两个参数:在其中运行函数的作用域,另一个是传递给函数的参数逐个列出;
-
二者最强大的用途是可以扩充函数赖以运行的作用域,且对象不需要与方法有任何耦合关系:
window.color = "red";
var o = { color: "blue" };
function sayColor(){
alert(this.color);
}
sayColor(); //red
sayColor.call(this); //red
sayColor.call(window); //red
sayColor.call(o); //blue
-
bind()是ECMAScript5定义的,创建一个函数的实例,其this值会被绑定到传给bind()函数的值
window.color = "red";
var o = { color: "blue" };
function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); //blue
四、函数返回值
-
即使函数确实有值,也不必明确地声明它。该函数只需要使用 return 运算符后跟要返回的值即可。
-
与在 Java 中一样,函数在执行过 return 语句后立即停止代码。因此,return 语句后的代码都不会被执行。
-
如果函数无返回值,那么可以调用没有参数的 return 运算符,随时退出函数。它真正返回的值是 undefined。
五、函数的执行
( function(){…} )()和( function (){…} () )是两种javascript立即执行函数的常见写法。
匿名函数适合用来定义再整个脚本里只出现一次的函数:匿名函数没有名字,只能在哪里定义,在哪里使用。
-
方式1,调用函数,得到返回值。强制运算符使函数调用执行
(function(x,y){
alert(x+y);
returnx+y;
}(3,4));
-
方式2,调用函数,得到返回值。强制函数直接量执行再返回一个引用,引用再去调用执行
(function(x,y){
alert(x+y);
returnx+y;
})(3,4);
这种方式也是很多库爱用的调用方式,如jQuery,Mootools。
-
方式3,使用void
void function(x) {
x = x-1;
alert(x);
}(9);
-
方式4,使用-/+运算符
-function(x,y){
alert(x+y);
returnx+y;
}(3,4);
+function(x,y){
alert(x+y);
returnx+y;
}(3,4);
--function(x,y){
alert(x+y);
returnx+y;
}(3,4);
++function(x,y){
alert(x+y);
returnx+y;
}(3,4);
-
方式5,使用波浪符(~)
~function(x, y) {
alert(x+y);
returnx+y;
}(3, 4);
-
方式6,匿名函数执行放在中括号内
[function(){
console.log(this) // 浏览器得控制台输出window
}(this)]
-
方式7,匿名函数前加typeof
typeoffunction(){
console.log(this) // 浏览器得控制台输出window
}(this)
-
方式8,匿名函数前加delete
deletefunction(){
console.log(this) // 浏览器得控制台输出window
}(this)
-
方式9,匿名函数前加void
void function(){
console.log(this) // 浏览器得控制台输出window
}(this)
-
方式10,使用new方式,传参
newfunction(win){
console.log(win) // window
}(this)
-
方式11,使用new,不传参
newfunction(){
console.log(this) // 这里的this就不是window了
}
-
方式12,逗号运算符
1, function(){
console.log(this) // window
}();
-
方式13,按位异或运算符
1^function(){
console.log(this) // window
}();
-
方式14,比较运算符
1>function(){
console.log(this) // window
}();
最后看看错误的调用方式
function(x,y){
alert(x+y);
returnx+y;
}(3,4);