zoukankan      html  css  js  c++  java
  • JavaScript【引用类型】Function 类型

    以下大部分为学习《JavaScript 高级程序设计》》(第 3 版) 所做笔记。

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

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

       2、立即执行函数

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

       4没有重载

       5函数声明与函数表达式

       6作为值的函数

       7函数内部属性

       8函数属性和方法

    定义函数的几个方法:

     定义函数的方式有 2 种:一种是函数声明,另一种是函数表达式。

     1 <script>
     2     //1、函数声明
     3         function functionName(arg0, arg1, arg2){
     4             //函数体
     5         };
     6         //Firefox、Safari、Chrome 和 Opera 给函数定义一个非标准的 name 属性,通过这个属性可以访问到函数指定的名字
     7         console.log( functionName.name );   //输出:functionName
     8     
     9     //2、函数表达式
    10         //创建一个函数并将它赋值给 functionName2 ,这种形式创建的函数叫做匿名函数(或者叫拉姆达函数),因为 function 关键字后面没有标识符。
    11         var functionName2 = function(arg0, arg1, arg2){
    12             //函数体
    13         };
    14     
    15     //3、使用function构造函数
    16         //不推荐使用,最后一个参数被看作是函数体
    17         var sum = new Function("num1", "num2", "return num1 + num2");
    18         console.log(sum(3, 4));        //输出:7
    19     </script>

    立即执行函数(IIFE)

    匿名函数属于函数表达式。匿名函数的形式是 function( 形参列表 ){ 函数体 } 。立即执行函数的形式是 ( function( 形参列表 ){ 函数体 }( 实参列表 ) ); 或者 ( function( 形参列表 ){ 函数体 } )( 实参列表 ); 。对括号的理解可以理解为 JS 里括号() 有求值的作用,括号里是函数就是起到执行函数的作用,记住就行。

     1 <script>
     2 //几种正确的使用方式:
     3     //( function(){...}() );
     4     ( function(num1, num2){
     5         console.log( num1 + num2 );
     6     }(1, 2) );   //输出:3
     7 
     8     //( function(){...} )();
     9     ( function(num3, num4){
    10         console.log( num3 + num4 )
    11     })(1, 2);    //输出:3
    12 
    13     //var functionName =  ( function(){...}() );
    14     var fn1 = ( function(num5, num6){
    15         console.log( num5 + num6 );
    16     }(1, 2) );   //输出:3
    17 
    18     //var functionName =  ( function(){...} )();
    19     var fn2 = ( function(num7, num8){
    20         console.log( num7 + num8 );
    21     }(1, 2) );   //输出:3
    22 
    23 //缺少括号是错误的使用方式,比如:function(){...}();
    24 //缺少括号但是匿名函数前有+/-/!也可以实现立即执行函数
    25     //+
    26     + function(num1, num2){
    27         console.log( num1 + num2 );
    28     }(1, 2);  //输出:3
    29     //-
    30     - function(num3, num4){
    31         console.log( num3 + num4 );
    32     }(1, 2);  //输出:3
    33     //
    34     ! function(num7, num8){
    35         console.log( num7 + num8 );
    36     }(1, 2);  //输出:3
    37 </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>

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

     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>
  • 相关阅读:
    jsp页面增加语音播报
    tomcat页面重定向跳转
    飘窗
    将回车键与页面ID绑定
    例35:十进制转二进制
    例33:求100-200间素数
    例30:尼科彻斯定理
    例29:哥德巴赫猜想
    例28:斐波那契数列
    例27:哈希查找
  • 原文地址:https://www.cnblogs.com/xiaoxuStudy/p/12354095.html
Copyright © 2011-2022 走看看