美文网首页饥人谷技术博客
引用类型之Function类型

引用类型之Function类型

作者: 少年vv | 来源:发表于2016-12-04 15:39 被阅读0次

    对于面向对象编程的语言来说,对象是很重要的一个概念,而对于函数来说,每个函数实际上都是对象,每个函数都是Function类型的实例,而且与其他引用类型一样具有属性和方法。

    函数声明与函数表达式

    通常有三种声明函数的方法

    1. 使用函数声明语法
    function sum(num1, num2) {
    return num1 + num2;
    }
    

    这也是最常用的方法

    1. 使用函数表达式定义函数
    var sum = function (num1, num2) {
    return num1 + num2;
    };
    

    可能会注意到function关键字后面没有函数名,这是因为使用函数表达式定义函数时,通过变量sum就可以引用函数

    1. 使用Function构造函数
    var sum = new Function("num1", "num2", "return num1 + num2");
    

    但是非常不推荐这种写法,因为这种语法会导致解析两次代码(第一次解析ECMAScript代码,第二次解析传入构造函数的参数)从而影响性能

    关于变量提升

    对于1,2两种声明函数的方法有什么不同呢?看下面这个例子

    // 使用函数声明创建函数
    console.log(sum(10,10));  //会打印出20
    function sum(num1, num2) {
      return num1 + num2;
    };
    
    // 使用函数表达式创建函数
    console.log(add(10,10)); //会报错
    var add = function(num1, num2) {
      return num1 + num2;
    };
    

    实际上,解析器在执行环境中加载数据时,解析器会率先读取函数声明,并使其在执行任何代码之前可用,而至于函数表达式,则必须等到解析器执行到它所在的代码行才会真正被解释执行。

    函数内部属性

    在函数内部,有两个特殊的对象:argumentsthis

    arguments是一个类数组对象,包含着传入函数的所有参数,之前在基础算法的时候已经讲过。但是arguments还有一个名叫callee属性,该属性是一个指针,指向拥有arguments对象的函数。具体用法之前写过了,看这里

    另一个比较特殊的对象就是this了,关于this知乎上@方方老师这篇文章讲的特别好

    函数的属性和方法

    因为在ECMAScript中函数是对象,因此函数也有属性和方法。

    每个函数包含两个属性:lengthprototype

    length表示函数接受的参数的个数

    function sayName(name) {
      console.log(name);
    }
    
    function sum(sum1, sum2) {
      return num1 + num2;
    }
    
    function sayHi() {
      console.log("Hi!");
    }
    
    console.log(sayName.length);  //1
    console.log(sum.length);      //2
    console.log(sayHi.length);    //0
    

    另一个属性prototype是保存引用类型所有实例方法的真正所在,比如toString()valueOf()等方法都保存在prototype名下,prototype在实现继承时非常重要,下一篇我们再讲。

    每个函数都包含两个非继承来的方法:apply()call()

    apply()call()都是在特定的作用域中调用函数,等于设置函数体内this的值,他们的区别在于:
    apply()接受两个参数:一个是在其中运行函数的作用域,另一个是参数数组,既可以是Array实例,也可以是arguements对象。
    call()第一个参数和apply()一样,但是传递参数的时候,必须逐个例举出来。

    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必须把参数列举出来
    }
    
    console.log(callSum1(10,10));   //20
    console.log(callSum2(10,10));   //20
    console.log(callSum3(10,10));   //20
    

    既然apply()call()的参数有作用域,那么是用来干什么的呢?看下面的例子:

    window.color = "red";
    var 0 = { color: "blue" };
    
    function sayColor() {
      console.log(this.color);
    }
    
    sayColor();                //red
    sayColor.call(this)        //red
    sayColor.call(window)      //red
    sayColor.call(o)           //blue
    

    是不是this的值又懵了?如果懵了,就翻上去看方方老师那篇文章。
    没错,apply()call()的作用就是扩充函数的作用域

    大概就是这么多了,书上这一章的内容我反复看了好几遍才理解,所以学习哪有什么捷径,无他,唯手熟尔
    那么,聪明的你,看完之后懂了没有?
    下一篇准备讲原型

    相关文章

      网友评论

        本文标题:引用类型之Function类型

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