ECMAScript的函数是对象,函数名是指针

创建:

函数声明法:

  1. function sum (num1, num2) {  
  2.     return num1 + num2;  

函数表达式法:

  1. var sum = function(num1, num2) {  
  2.     return num1 + num2;  
  3. }; 

函数表达式法:这种不推荐,因为这种语法会导致解析两次代码(第一次解析常规ECMAScript代码,第二次解析传入构造函数中的字符串),从而影响性能

  1. var sum = new Function("num1""num2""return num1 + num2");   //不推荐 

同时使用函数声明和函数表达式:这种语法会在Safari出错

  1. var sum = function sum () {} 

由于函数名只是指针,所以如下:

 

  1. function sum(num1, num2){  
  2.     return num1 + num2;  
  3. }          
  4. alert(sum(10,10));         //20  
  5.           
  6. var anotherSum = sum;          
  7. alert(anotherSum(10,10));  //20  
  8.           
  9. sum = null;          
  10. alert(anotherSum(10,10));  //20 

函数名是指针,所以没有重载:

 

  1. function addSomeNumber (num) {  
  2.     return num + 100;  
  3. }  
  4.  
  5. function addSomeNumber (num) {  
  6.     retrun num + 200;  
  7. }  
  8.  
  9. var result = addSomeNumber(100); //300 

上面代码实际上是:

  1. function addSomeNumber (num) {  
  2.     return num + 100;  
  3. }  
  4.  
  5. addSomeNumber = function (num) {  
  6.     retrun num + 200;  
  7. }  
  8.  
  9. var result = addSomeNumber(100); //300 

创建第二个函数时,改变了addSomeNumber的指向

函数声明与函数表达式的一个区别:

解析器会率先读取函数声明,并使其在执行任何代码前可用;而函数表达式,必须等到解析器执行到所在行,才能被解释执行

  1. alert(sum(10,10));              //20  
  2.       
  3. function sum(num1, num2){  
  4.     return num1 + num2;  

如果改成如下,就会报错

  1. alert(sum(10,10));              //causes an error  
  2.       
  3. var sum = function(num1, num2){  
  4.     return num1 + num2;  
  5. };  

把函数当值使用:

将一个函数作为另一个函数的结果返回

  1. function callSomeFunction(someFunction, someArgument){  
  2.     return someFunction(someArgument);  
  3. }  
  4.  
  5. function add10(num){  
  6.     return num + 10;  
  7. }  
  8.           
  9. var result1 = callSomeFunction(add10, 10);  
  10. alert(result1);   //20  
  11.           
  12. function getGreeting(name){  
  13.     return "Hello, " + name;  
  14. }  
  15.           
  16. var result2 = callSomeFunction(getGreeting, "Nicholas");  
  17. alert(result2);   //Hello, Nicholas 

从一个函数中返回另一个函数,如给对象数组排序:(默认情况下,sort()会调用toString()方法)

  1. function createComparisonFunction(propertyName) {  
  2.           
  3.     return function(object1, object2){  
  4.         var value1 = object1[propertyName];  
  5.         var value2 = object2[propertyName];  
  6.           
  7.         if (value1 < value2){  
  8.             return -1;  
  9.         } else if (value1 > value2){  
  10.             return 1;  
  11.         } else {  
  12.             return 0;  
  13.         }  
  14.     };  
  15. }  
  16.  
  17. var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];  
  18.           
  19. data.sort(createComparisonFunction("name"));  
  20. alert(data[0].name);  //Nicholas  
  21.           
  22. data.sort(createComparisonFunction("age"));  
  23. alert(data[0].name);  //Zachary   

函数内部属性:

函数内部有两个特色的对象 arguments 和 this

arguments:是一个类数组对象,包含传入函数的所有参数

callee:是arguments的属性,该属性是一个指针,指向拥有这个arguments对象的函数

下面是一个经典的阶乘例子:

  1. function factorial(num){  
  2.     if (num <= 1) {  
  3.         return 1;  
  4.     } else {  
  5.         return num * arguments.callee(num-1)  
  6.     }  
  7. }  
  8.  
  9. var trueFactorial = factorial;  
  10.           
  11. factorial = function(){  
  12.     return 0;  
  13. };  
  14.           
  15. alert(trueFactorial(5));   //120  
  16. alert(factorial(5));   //0 

this:引用的是函数据以执行的环境对象(当在网页的全局作用域中调用函数时,this对象引用的就是window)

  1. window.color = "red";  
  2. var o = { color: "blue" };  
  3.           
  4. function sayColor(){  
  5.     alert(this.color);  
  6. }  
  7.           
  8. sayColor();     //red  
  9.           
  10. o.sayColor = sayColor;  
  11. o.sayColor();   //blue 

caller:这个属性中保存着调用当前函数的函数的引用,如果在全局作用域中调用当前函数,它的值为null(Opera9.6版之前不支持该属性)

  1. function outer(){  
  2.     inner();  
  3. }  
  4.           
  5. function inner(){  
  6.     alert(inner.caller);  
  7. }  
  8.           
  9. outer();              //function outer(){  
  10.                       //    inner();  
  11.                       //} 

下面这种写法与上面同理,只是达到了更好的松耦合,这样函数名称可以变动而不用改变内部代码

  1. function outer(){  
  2.     inner();  
  3. }  
  4.           
  5. function inner(){  
  6.     alert(arguments.callee.caller);  
  7. }  
  8.           
  9. outer();              //function outer(){  
  10.                       //    inner();  
  11.                       //} 

注意:

1.这严格模式下,访问 arguments.callee 会导致错误。

2.ECMAScript5 还定义了 arguments.caller 属性,但在严格模式下也会导致错误,而在非严格模式下这个属性始终是undefined。定义这个属性是为了分清 arguments.caller 和 函数的caller属性。以上都是为了加强这门语言的安全性,这样第三方代码就不会在相同的环境里窥视其他代码了。

3.在严格模式下,不能给函数的caller属性赋值,否则会出错。

函数属性和方法:

由于在ECMAScript中,函数是对象,所以函数有属性和方法

length:表示函数希望接收的命名参数的个数

  1. function sayName(name){  
  2.     alert(name);  
  3. }        
  4.           
  5. function sum(num1, num2){  
  6.     return num1 + num2;  
  7. }  
  8.           
  9. function sayHi(){  
  10.     alert("hi");  
  11. }  
  12.           
  13. alert(sayName.length);  //1  
  14. alert(sum.length);      //2  
  15. alert(sayHi.length);    //0 

prototype:第6章

apply():用途是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值

需传入2个参数:该运行函数的作用域(this)、参数数组

  1. function sum(num1, num2){  
  2.     return num1 + num2;  
  3. }  
  4.           
  5. function callSum1(num1, num2){  
  6.     return sum.apply(this, arguments);  //由于在全局作用域中调用的,所以this指的是window对象  
  7. }  
  8.           
  9. function callSum2(num1, num2){  
  10.     return sum.apply(this, [num1, num2]);  
  11. }  
  12.           
  13. alert(callSum1(10,10));   //20  
  14. alert(callSum2(10,10));   //20 

注意:在严格模式下,未指定环境对象而调用函数,则this值不会转型为window。除非明确把函数添加到某个对象 或者 调用apply()或call(),否则this值将是undefined

call():用途是在特定的作用域中调用函数

传入参数:该运行函数的作用域(this)、逐一列出参数

  1. function sum(num1, num2){  
  2.     return num1 + num2;  
  3. }  
  4.           
  5. function callSum(num1, num2){  
  6.     return sum.call(this, num1, num2);  
  7. }  
  8.           
  9. alert(callSum(10,10));   //20 

apply()和call()真正的用武之地是扩充函数赖以运行的作用域,如下:

  1. window.color = "red";  
  2. var o = { color: "blue" };  
  3.           
  4. function sayColor(){  
  5.     alert(this.color);  
  6. }  
  7.           
  8. sayColor();             //red  
  9.           
  10. sayColor.call(this);    //red  
  11. sayColor.call(window);  //red  
  12. sayColor.call(o);       //blue 

使用apply()或call()来扩充作用域的最大的好处,就是对象不需要与方法有任何耦合关系(这跟之前那个版本比(讲this时),省下很多多余的步骤)

bind():把this值与该函数绑定

  1. window.color = "red";  
  2. var o = { color: "blue" };  
  3.                              
  4. function sayColor(){  
  5.     alert(this.color);  
  6. }  
  7. var objectSayColor = sayColor.bind(o);  
  8. objectSayColor();      //blue 

把o与objectSayColor的this绑定,所以调用时返回的是blue,而不是red,第22章

支持bind()的浏览器有IE9+、Firefox 4+、Chrome……

每个函数继承的toLocaleString()、toString()、valueOf()都返回的函数的代码,因浏览器而异。