美文网首页
2018-11-16

2018-11-16

作者: kathyever | 来源:发表于2018-11-16 17:23 被阅读0次

    打卡时间:

    Function类型

    每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。函数通常是使用函数声明语法定义的,例:

    function sum(num1,num2){
        return num1+num2;
    }
    
    //上面的函数声明语法与下面的函数表达式 定义函数的方式几乎相差无几
    
    var sum=function(sum1,sum2){
        return num1+num2;
    };// 函数末尾有一个分号,就像其他声明变量时一样。
    
    

    最后一种定义函数的方式是使用Function构造函数。Function构造函数可以接受任意数量的参数,但最后一个参数始终都被看成是函数体,而前面的参数则枚举除了新函数的参数。例:

    var sum = new Function("num1","num2","return num1+num2");
    //这是一个函数表达式。但是不推荐!因为这种语法会导致解析两次代码从而影响性能。
    

    函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他函数没有说明不同。也就是说一个函数可能会有多个姓名。例:

    function sum(num1,num2){//定义了名为sum()的函数
        return num1+num2;
    }
    alert(sum(10,10));//20
    
    var anotherSum = sum;//声明变量anotherSum
    alert(anotherSum(10,10));//20
    //注意!使用不带圆括号的函数名是访问函数指针,而非调用函数。
    //此时,anotherSum和sum就都指向了同一个函数,即使将sum设置为null,但仍然可以正常调用anotherSum()
    sum = null;
    alert(anotherSum(10,10));//20
    

    没有重载(深入理解)

    function addSomeNumber(num){
        return num+100;
    }
    function addSomeNumber(num){
        return num+200;
    }
    var result = addSomeNumber(100);
    

    在创建第二个函数时,实际上覆盖了引用第一个函数的变量addSomeNumber

    函数声明与函数表达式

    解析器在向执行环境中加载数据时,对函数声明和函数表达式并非一视同仁。
    解析器会率先读取函数声明,并使其在执行任何代码之前可用。而函数表达式则必须等到解析器执行到它所在的代码行,才真正被解释执行。例:

    alert(sum(10,10));
    function sum(num1,num2){
        return num1+num2;
    }//代码开始执行之前,解析器就已经通过一个名为函数声明提升的过程,读取并将函数声明添加到执行环境中
    
    alert(sum(10,10));
    var sum = function(num1  ,num2){
        return num1 + num2;
    };//以上代码之所以会在运行期间产生错误,原因在于函数位于一个初始化的语句中,而不是一个函数声明。换句话说,在执行到函数所在语句之前,变更sum中不会保存有对函数的引用 。 
    

    除了什么时候可以通过变量访问函数这一点区别之外,函数声明与函数表达式的语法其实是等价的。

    作为值的函数

    因为ECMAScript中的函数名本身就是变量,所以函数也可以作为值来使用。也就是说,不仅可以像传递参数一样把一个函数传递给另一个函数,而且将一个函数作为另一个函数的结果返回。

    function callSomeFunction(someFunction,someArgument){
        return someFunction(someArgument);
    }
    
    function add10(num){
          return num+10;
    }
    
    var result = callSomeFunction(add10,10);
    alert(result);//20
    
    function getGreeting(name){
        return "Hello," + name;
    }
    
    var result2 = callSomeFunction(getGreeting, "Nicholas");
    alert(result2);//"Hello , Nicholas"
    
    

    这里的callSomeFunction()函数是通用的。无论第一个参数中传递进来的是什么函数,它都会返回执行第一个参数后的结果。
    要访问函数的指针而不执行函数的话,必须去掉函数名后面的那对圆括号
    因此上面的例子中传递给callSomeFunction()的是add10和getGreeting,而不是执行它们之后的结果。

    假设我们要根据某个对象属性对数组进行排序。而传递给数组sort()方法的比较函数要接收两个参数,即要比较的值,那我们就需要一种方式来指明按照哪个属性来排序。
    通过下面这个函数的定义,定义一个函数,它接受一个属性名,然后根据这个属性名来创建一个比较函数。

    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;
                }
        };
    }
    

    看似复杂其实就是在一个函数中嵌套了另一个函数。而且内部函数前面加了一个return操作符。在内部操作符接收到propertyName参数后,它会使用方括号表示法来取得给定属性的值。
    取到了想要的属性值之后,就可以定义比较函数啦,例:↓

    var data = [
          {name:"kathy", age:18},
          {name:"stephen", age:19}
    ];
    
    data.sort(createComparisonFunction("name"));
    alert(data[0].name);//kahty
    
    data.sort(createComparisonFunction("age"));
    alert(data[1].age);//19
    
    

    函数内部属性

    在函数内部,有两个特殊的对象:arguments和this。
    this代表函数作用域对象;arguments是函数的参数数组

    arguments它是一个类数组对象,包含着传入函数中的 所有参数,主要用途是保存函数参数。但这个对象还有一个名叫callee的属性,是一个指针,指向拥有这个arguments对象的函数。例如下面的这个非常经典的阶乘函数。

    function factorial(num){
        if (num<=1){
            return 1;
        }else{
            return num*factorial(num-1)
        }
    }
    //阶乘函数一般都要用到递归算法。函数中有名字,而且在名字不会变的情况下,这样定义是没有问题的。
    

    但是上面函数的执行与函数名factorial紧紧耦合在一起,为了消除,可以如下面这样使用arguments.collee。

    function factorial(num){
        if (num<=1){
            return 1;
        }else{
            return num*arguments.collee(num-1)
        }
    }
    
    
    var trueFactorial = factorial;
    
    factorial = function(){
        return 0;
    };
    alert(trueFactorial (5));// returns 120 (5 * 4 * 3 * 2 * 1)
    alert(factorial(5));//0
    
    image.png
    image.png



    函数内部的另一个特殊对象是this。this引用的是函数据以执行的环境对象——或者也可以说是this值(当在网页的全局作用域中调用函数时,this对象引用的就是window)。例:

    window.color = "red";
    var o = { color:"blue"};
    
    function sayColor(){
        alert(this.color);
    }
    
    sayColor();//"red"
    
    o.sayColor =sayColor;
    o.sayColor ();//"blue"
    

    函数的名字仅仅是一个包含指针的变量而已。及时是在不同的环境中,全局的sayColor()和o.sayColor ()指向的仍然是同一个函数

    ECMAScript也规范了另一个函数对象的属性:caller。这个属性保存着调用当前函数的函数的引用,如果是全局作用域中调用当前函数,它的值为null。

    function outer(){
        inner();
    }
    function inner(){
        alert(inner.caller);
    }
    outer();
    

    以上代码会输出outer()函数的源代码。因为outer()调用了inter(),所以inner.caller就指向了outer()。
    也可以通过arguments.callee.caller来防蚊同样的信息。

    function outer(){
        inner();
    }
    function inner(){
        alert(arguments.callee.caller);
    }
    outer();
    

    严格模式下不能为函数的caller属性赋值,否则会导致错误。

    相关文章

      网友评论

          本文标题:2018-11-16

          本文链接:https://www.haomeiwen.com/subject/hkypfqtx.html