ECMAScript中的函数是对象,与其他引用类型一样具有属性和方法。因此,函数名实际是一个指向函数对象的指针。
函数声明
function sum(num1,num2){
return num1+num2;
}//函数声明
var sum = function(num1,num2){
return num1+num2;
}; //函数表达式 这里的分号很重要
没有重载
function addSomeNumber(num){
return num + 100;
}
function addSomeNumber(num){
return num + 200;
}
var result = addSomeNumber(100); //300
创建第二个函数时覆盖了引用第一个函数的变量addSomeNumber。
函数声明与函数表达式
alert (sum(10,10));
function sum(num1,num2){
return num1+num2;
}
这样的代码可以正常执行。代码开始执行前,解析器会率先读取函数声明并将其添加到执行环境中,对代码求值前,JS引擎在第一遍会声明函数并将它们放到源代码树的顶部。但改为函数表达式就会出错。
作为值的函数
- 像传递参数一样把一个函数传递给另一个函数
function callSomeFunction(someFunction,someArgument){
return someFunction(someArgument);
}
function add10(num){
return num+10;
}
var result1 = callSomeFunction(add10,10);
alert(result1); //20
function getGreeting(name){
return "Hello"+name;
}
var result2 = callSomeFunction(getGreeting,"Mike");
alert(result2); //Hello Mike
//callSomeFunction是通用的,函数作为第一个参数传递进去,返回执行第一个参数后的结果
- 从一个函数中返回另一个函数
function createComparisonFunction(propertyName){
return function(object1,object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if(value1<value2){
return -1;
}else if(value1>value2){
return 1;
}else{
return 0;
}
}
}
var date = [{name:"Mike", age:28},{name:"Amy", age:29}];//创建包含两个对象的数组
date.sort(creatComparisonFunction("name"));
alert(date[0].name);//Amy
date.sort(creatComparisonFunction("age"));
alert(date[0].name);//Mike
函数内部属性
- arguments:保存函数参数的类数组对象
- arguments.callee:是一个指针,指向拥有这个arguments对象的函数
function factorial(num){
if(num<=1){
return 1;
}else{
return num * arguments.callee(num-1);//消除耦合现象
}
}
//消除耦合后,无论函数使用什么名字都可以正常调用
var trueFactorial = factorial;
factorial =function(){
return 0;
};//factorial函数已经变为简单的返回0的函数
alert(trueFactorial(5)); //120
alert(factorial(5)); //0
- this对象
window.color = "red";
var o ={color: "blue" };
function sayColor(){
alert(this.color);
}
sayColor(); //"red" 全局作用域调用时 this.color求值转换为window.color求值
o.sayColor = sayColor; //函数对象赋给o
o.sayColor(); //"blue" this.color转换为o.color
注:函数名仅是一个包含指针的变量,即使在不同执行环境,全局sayColor()函数与o.sayColor()指向的是同一个函数。
- caller对象
function outer(){
inner();
}
function inner(){
alert(arguments.callee.caller);
}
outer();
我们来看一个例子
function func1(num){
if(num==1){
return num;
}else{
return num*func1(num-1);
}
}
var func=func1; //由于这里是赋值操作,所以调用func时会找这个式子之前的func1,到func1内部时,调用下面func1
func1 = function (){ //函数表达式声明
return 1;
};
alert(func(3)); //3
- 当第二次声明换成函数声明时,结果为1。因为解析器有一个函数声明提升的过程。
- 当第一次声明func1,返回值写为
return num * arguments.callee(num-1);
,结果为6。这是因为消除了耦合现象。
函数属性和方法
- length属性 表示函数希望接收的命名参数的个数
function sayName(name){
alert(name);
}
function sum(num1,num2){
return num1 + num2;
}
function sayHi(){
alert("hi");
}
alert(sayName.length);//1
alert(sum.length);//2
alert(sayHi.length);//0
- apply()和call()方法:在特定的作用域中调用函数
apply():一个参数是在其中运行函数的作用域,另一个是参数数组(可是Array实例,也可以是Arguments对象)。
call(): 第一个参数this值没有变化,只是其余参数需要逐个列举。
function sum(num1,num2){
return num1 + num2;
}
function callSum1(num1,num2){
return sum.apply(this,arguments);//传入arguments对象
}
function callSum2(num1,num2){
return sum.apply(this,[num1,num2]);//传入数组
}
function callSum3(num1,num2){
return sum.call(this,num1,num2);//call()接收参数的方式不同
}
alert(callSum1(10,10)); //20
alert(callSum2(10,10)); //20
alert(callSum3(10,10)); //20
- 两个方法可以扩充函数赖以运行的作用域
好处:对象不需要与方法有任何耦合关系
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()方法:会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。
window.color = "red";
var o = {color: "blue"};
function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o);//sayColor()调用bind()并传入对象o,创建objectSayColor()函数,objectSayColor()函数this值变为o
objectSayColor(); //blue