JavaScript【引用类型】Function 类型

函数是Function类型的实例,具有属性和方法。函数是对象,函数名是一个指向函数对象的指针。

目录:1、定义函数的几个方法

   2、函数名仅仅是指向函数的指针。一个函数可能有多个名字

   3、没有重载

   4、函数声明与函数表达式

   5、作为值的函数

   6、函数内部属性

   7、函数属性和方法

定义函数的几个方法:

 1 <script>
 2     //方法1. 使用函数声明语法定义
 3     function sum1(num1, num2){
 4         return num1 + num2;
 5     }
 6     console.log(sum1(1, 2))        //输出:3
 7 
 8     //方法2. 使用函数表达式定义
 9     var sum2 = function(num1, num2){
10         return num1 + num2;
11     };
12     console.log(sum2(2, 3));        //输出:5
13 
14     //方法3. 使用function构造函数
15     //不推荐使用,最后一个参数被看作是函数体
16     var sum3 = new Function("num1", "num2", "return num1 + num2");
17     console.log(sum3(3, 4));        //输出:7
18 </script>

函数名仅仅是指向函数的指针。一个函数可能有多个名字。

 1 <script>
 2     function sum(num1, num2){
 3         return num1 + num2;
 4     }
 5     console.log(sum(2, 2));        //输出: 4
 6 
 7     var another = sum;             //此时 another 跟 sum 都指向了同一个函数
 8     console.log(another(2, 2));    //输出:4
 9 
10     sum = function(){
11         return 0;
12     };
13     console.log(sum(2, 2));           //输出:0
14     console.log(another(2, 2));     //输出:4
15 </script>

没有重载

如果声明了两个函数同名,则后声明的函数将覆盖前声明的函数。

 1 <script>
 2     //使用函数声明语法定义函数时
 3     function num(num1){
 4         return num1 + 10;
 5     }
 6     function num(num1){
 7         return num1 + 20;
 8     }
 9     console.log(num(1));    //输出:21
10 
11     //使用函数表达式定义函数时
12     var num = function(num1){
13         return num1 + 30;
14     }
15     var num = function(num1){
16         return num1 + 40;
17     }
18     console.log(num(1));    //输出:41
19 </script>

 

函数声明与函数表达式

在代码执行之前,解析器有一个函数声明提升的过程。函数提升的过程即读取并且将函数声明添加到执行环境中的过程。

使用函数声明语法定义函数,可以先调用函数再定义函数。

1    console.log(num(1));    //输出:11
2     function num(num1){
3         return num1 + 10;
4     }

使用函数表达式定义函数,不可以先调用函数再定义函数。

1     console.log(num(1));    
2     var num = function(num1){
3         return num1 + 10;
4     }
5     //报错:Uncaught TypeError: num is not a function

作为值的函数

函数也可以作为值。去掉函数名后面的圆括号,则只访问函数的指针不执行函数。

 1 <script>
 2     //可以像传递参数一样将函数传递给另一个函数
 3     //这里像传递参数一样将函数someFunction传递给另一个函数 functionOne
 4     function functionOne(someFunction, someArgument){
 5         //可以将一个函数作为另一个函数的结果返回
 6         //这里将函数 someFunction 作为另一个函数 functionOne 的结果返回
 7         //这里 functionOne 函数接受2个参数,第一个参数是一个函数即 someFunction, 第二个参数 someArgument 是传递给函数 someFunction 的一个值
 8         return someFunction(someArgument);
 9     }
10     function functionTwo(num){
11         return num + 10;
12     }
13     var result = functionOne(functionTwo, 100);
14     console.log(result);        //输出:110
15 </script>

可以从一个函数中返回另一个函数。可以根据某个对象属性对数组进行排序:

 1 <script>
 2     //从一个函数中返回另一个函数
 3     //定义函数createComparisonFn接收属性名propertyName
 4     function createComparisonFn(propertyName){
 5         //比较函数接收2个参数
 6         return function(a, b){
 7             //根据属性名propertyName创建一个比较函数
 8             var value1 = a[propertyName];
 9             var value2 = b[propertyName];
10             if(value1 < value2){
11                 //如果value1 应该位于 value2 之前则返回一个负数
12                 return -1;
13             }else if(value1 > value2){
14                 //如果value1 应该位于 value2 之后则返回一个正数
15                 return 1;
16             }else{
17                 //如果value1 = value2 则返回0
18                 return 0;
19             }
20         };
21     }
22     var data = [{name: "xiaoxu", age:20 }, {name: "zhangsan", age: 10}];
23     //将比较函数createComparisonFn传递给数组sort()方法
24     //指明按照对象的 name 属性来比较
25     data.sort(createComparisonFn("name"));
26     console.log(data[0].name);        //输出:xiaoxu
27     //指明按照对象的 age 属性来比较
28     data.sort(createComparisonFn("age"));
29     console.log(data[0].age);        //输出:10
30 </script>

函数内部属性

callee

arguments 和 this 是函数内部的两个特殊对象。arguments 是一个包含传入函数中的所有参数的一个类数组对象。arguments 对象有一个 callee 属性。callee 属性是一个指向拥有 arguments 对象的函数的指针。在严格模式下访问 arguments.callee 会报错。

 1 <script>
 2     function factorial(num){
 3         if( num<=1 ){
 4             return 1;
 5         }else{
 6             console.log(arguments.callee);
 7         }
 8     }
 9     factorial();
10 </script>

输出:

可以看到执行语句“ console.log(arguments.callee); ”输出的是拥有arguments对象的函数factorial,  说明 callee 属性是一个指向拥有 arguments 对象的函数的指针。

定义一个阶乘函数:

1 <script>
2     function factorial(num){
3         if( num<=1 ){
4             return 1;
5         }else{
6             return num * factorial(num-1);
7         }
8     }
9 </script>

上面这样函数的执行与函数名 factorial 紧密耦合。使用 arguments.callee 可以消除这种紧密耦合的情况。

 1 <script>
 2     function factorial(num){
 3         if( num<=1 ){
 4             return 1;
 5         }else{
 6             //callee 属性是一个指向拥有 arguments 对象的函数的指针
 7             return num * arguments.callee(num-1)
 8         }
 9     }
10     //使用arguments.callee消除耦合之后,无论用什么函数名调用该函数都不影响执行。
11     var anotherName = factorial;
12     factorial = function(num){
13         return 0;
14     }
15     console.log(factorial(4));        //输出:0
16     console.log(anotherName(4));      //输出:24
17 </script>

this

this引用的是函数据以执行的环境对象。当在全局作用域中调用函数时 this 对象引用的是 window。

 1 <script>
 2     window.num = 1;
 3     var i = {
 4         num : 2
 5     }
 6     function sayNum(){
 7         console.log(this.num);
 8     }
 9     //在全局作用域中调用 sayNum 中时,this 引用的是全局对象 window,此时 this.color 等同于 window.color
10     sayNum();        //输出:1
11     //把函数赋给对象 i 并调用 i.sayNum()
12     i.sayNum = sayNum;
13     //this引用的是对象 i,此时 this.color 等同于 i.color
14     i.sayNum();        //输出:2
15 
16     //函数名仅仅时一个包含指针的变量,即使函数在不同的环境中执行,window.sayNum()函数跟i.sayNum()指向的仍是同一函数。
17     //但是对window.sayNum()或i.sayNum()进行更改,均不影响另一环境中的sayNum()函数。
18     //如下,对全局的sayNum()进行了更改,不影响i.sayNum()
19     sayNum = function(){
20         console.log("3");
21     };
22     sayNum();        //输出:3
23     i.sayNum();        //输出: 2
24     
25 </script>

caller

caller 是一个函数属性,保存着调用当前函数的函数的引用。

 1 <script>
 2     function outer(){
 3         //调用 inner 函数
 4         inner();
 5     }
 6     function inner(){
 7         console.log(inner.caller);
 8     }
 9     outer();    //输出:            ƒ outer(){
10                 //                            //调用 inner 函数
11                 //                            inner();
12                 //                        }
13     
14     //如果在全局作用域中调用,返回 null
15     inner();    //输出:null
16 </script>

如果想要解除紧密耦合,可以用 arguments.callee 代替函数名。

 1 <script>
 2     function outer(){
 3         //调用 inner 函数
 4         inner();
 5     }
 6     function inner(){
 7         console.log(arguments.callee.caller);
 8     }
 9     outer();    //输出:            ƒ outer(){
10                 //                            //调用 inner 函数
11                 //                            inner();
12                 //                        }
13     
14     //如果在全局作用域中调用,返回 null
15     inner();    //输出:null
16 </script>

 严格模式下不支持 arguments.caller ,在非严格模式下定义caller属性是 undefined。不支持向函数的caller属性赋值。

函数属性和方法

每个函数都有 length 跟 prototype 这两个属性。每个函数都有两个非继承而来的方法:apply() 和 call()。apply() 跟 call() 作用相同,区别在于接收参数的方式。bind() 方法会创建一个函数的实例,第一个参数 this 值会被绑定传给 bind() 函数的值。

length

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

1 <script>
2     function a(){}
3     function b( num ){}
4     function c( num1, num2){}
5     console.log( a.length );    //输出:0
6     console.log( b.length );    //输出:1
7     console.log( c.length );    //输出:2
8 </script>

prototype

prototype 保存引用类型的所有方法的真正所在。例如 toString() 跟 valueOf() 方法实际上都是保存在 prototype 之下。prototype 方法是不可枚举的。

apply()

apply() 接收2个参数。第一个参数是在其中运行的作用域,第二个参数可以是参数数组、Array的实例或者arguments对象。

 1 <script>
 2     function sum(num1, num2){
 3         return num1 + num2;
 4     }
 5     function applySum(num1, num2){
 6         //在执行sum()函数时传入this作为this值,因为是在全局作用域中调用的,所以传入的this就是window对象
 7         return sum.apply(this, arguments);
 8     }
 9     function applySum2(num1, num2){
10         return sum.apply(this, [num1, num2])
11     }
12     console.log(applySum(1, 2));    //输出:3
13     console.log(applySum2(1, 2));    //输出:3
14 </script>

call()

call() 的第一个参数是在其中运行的作用域,其余传给函数的参数必须逐个列举出来。

1 <script>
2     function sum(num1, num2){
3         return num1 + num2;
4     }
5     function applySum(num1, num2){
6         return sum.call(this, num1, num2)
7     }
8     console.log(applySum(1, 2));    //输出:3
9 </script>

apply() 跟 call() 的强大之处是他们可以扩充函数赖以生存的作用域。

 1 <script>
 2     window.num = 1;
 3     var i = {
 4         num : 2
 5     };
 6     function sayNum(){
 7         console.log( this.num );
 8     }
 9     //call()的第一个参数为运行函数的作用域
10     //在全局作用域中调用,this值等同于window
11     sayNum.call(this);        //输出:1
12     sayNum.call(window);    //输出:1
13     //在全局作用域中调用i,那么运行函数的作用域为对象 i。即先将sayNum()函数放到对象 i 中,然后再通过对象 i 来调用它
14     sayNum.call(i);            //输出:2
15 </script>

bind()

 1 <script>
 2     window.num = 1;
 3     var i = {
 4         num : 2
 5     };
 6     function sayNum(){
 7         console.log( this.num );
 8     }
 9     //创建一个函数实例 a 。sayNum() 调用 bind() 并传入对象 i, 创建 a() 函数。a函数的 this值等于 i。
10     var a = sayNum.bind( i );
11     //即使在全局作用域中调用 a(), 它的作用域仍为 i。
12     a();    //输出:2
13 </script>

猜你喜欢

转载自www.cnblogs.com/xiaoxuStudy/p/12354095.html