第五章 引用类型(5.Function类型)

  ·   JS高设(第三版)   ·   JavaScript     浏览量:
  • 函数的根源是对象。
  • 每个函数都是Function的实例,与其他引用类型一样具有属性和方法
  • 函数名是指向函数的指针,不会与某个函数绑定。

函数定义方法:

1.使用函数声明语法定义

    function sun (num1, num2) {
        return num1 + num2;
    }

2.使用函数表达式定义

    var sum = function(num1, num2) {
        return num1 + num2;
    };//此处又分号,因为他是一个变量

3.使用Function构造函数(不推荐)

    var sum = new Function("num1", "num2", "return num1 + num2");

不推荐使用此方法,因为会导致解析两次代码(一次是解析常规ECMASCript代码,一次是解析传入构造函数中的字符串)

由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没什么不同,换句话说一个函数可能会有多个名字

    function sum(num1, num2) {
        return num1 + num2;
    }
    consoloe.log(sum(10, 10)); // 20
    
    var anotherSum = sum;
    console.log(anotherSum(10, 10)); // 20
    
    sum = null;
    console.log(anotherSum(10, 10)); // 20

以上代码首先定义sum用于求和。
然后声明了anotherSum将sum赋值给他(不使用圆括号访问函数指针,使用圆括号是调用函数)。
sum=null,断绝sum与函数的关系
此时anotherSum仍然可以正常运行

没有重载(深入理解)

将函数名想象为指针,也有助于理解为什么ECMASCript没有函数重载的概念,以下是第三章中的例子

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

以上代码实际与以下没什么区别

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

通过观察重写之后的代码,很容易看清楚再船舰第二个函数时,实际上覆盖了引用第一个函数的变量

函数声明与函数表达式

解析器在像执行环境中加载数据时,对函数声明和函数表达式并非一视同仁。

  • 函数声明:解析器会率先读取函数声明,并使其在执行任何代码之前可用;
  • 函数表达式:必须等到解析器执行到他所在的代码行才会真正被解释执行。
    1

作为函数的值

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

当然也可以从一个函数中返回另一个函数
3
sort()使用方法

函数内部属性

arguments

1.保存函数参数
2.有一个calee(译:被召者)属性,指向拥有此arguments的函数,就是他爹
![4](http://hackbinimg.luokangyuan.com/20180928180955/4.jpg)
如果使用注释掉的代码,所有的返回值都将是0

this

this引用的是函数据以执行的环境对象,注意是函数的环境,不是this书写的函数内部环境
![5](http://hackbinimg.luokangyuan.com/20180928180978/5.jpg)
上图第一次调用时,this引用的是全局对象
将函数赋值给o之后,this引用的是对象o
所以输出结果不一样

函数属性和方法

因为ECMASCript中的函数是对象,因此函数也有属性和方法。
每个函数都有两个属性:

length

函数希望接受的命名参数的个数

prototype

对于引用类型而言,prototype保存了他们所有的实例方法(如toString(),valueOf()等),只不过是通过各自的实例访问罢了,EC5中,prototy是哦不可枚举的,不能用for-in发现,如下图
6

每个函数也都有两个方法,call()和apply()。
这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内的this对象的值。

apply()

接受两个参数,在其中运行函数的作用域,和参数数组(可以是Array的实例,也可以是arguments对象)
1

上图中,callSum1()在执行sum()时传入了他的this值作为sum的this值(也就是window对象)和arguments,而callSum2()传入了this和一个参数数组。这两个函数都会正常执行返回正确结果

call()

他与apply()的作用相同,他的第一个参数还是this,不同之处在于参数接收方式,他的其余参数必须逐个列举出来(想象为,打电话必须把电话数字全部列举出来)
2

事实上,传递参数并非apply()call()的真正用武之地;他们真正强大的地方在于能够扩充莱依韵兄的作用域
一目了然,不言而喻
3

上图中,第三次在传入O作为sayColor()的this作用域之后,打印出了blue



收起 >>
第五章 引用类型(5.Function类型)