zoukankan      html  css  js  c++  java
  • 第十一章 Function类型

      在ECMAScript中,Function(函数)类型实际上是对象。每个函数也是Function类型的实例,而且都与其它引用类型一样具有属性和方法。由于是函数对象,因此函数名实际上也是一个指向函数对象的指针。

    一、函数的声明方式

      函数通常是使用函数声明语法定义:

      1、普通的函数声明

      function sum(sum1,sum2){

      return sum1+sum2;

      }

      2、使用变量初始化函数

      var sum=function(){

      return sum1+sum2;

      }

      3、使用function构造函数

      var sum=new Function("sum1","sum2","return sum1+sum2");  //不推荐 因为这种会导致解析两次代码,一次解析常规ECMAScript,一次解析传入构造函数中的字符串

    二、作为值类型

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

      function callSomeFunction(someFunction,someArgument){

        return someFunction(someArgument);

      }

      这个函数接受两个参数。第一个参数应该是一个函数,第二个参数应该是要传递给该函数的一个值。

      function someFunction(someArgument){

        return  someArgument+100;

      }

      var result=callSomeFunction(someFunction,100);     //200

    三、函数内部属性

    在函数内部,有两个特殊的对象:agruments和this。其中,arguments是一个类型组对象,包含着传入函数中的所有参数。虽然arguments的主要用途是保存函数参数,但这个对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。

      function factorial(num){

        if(num<=1){

          return  1;

        } else {

          return num * factorial(num-1);

        }

      }

      定义阶乘函数一般用到递归算法;如果上面的代码所示,在函数有名字,而且名字以后也不会变的情况下,这样定义是没有问题的。但问题是这个函数的执行与函数名factorial紧紧耦合在一起。为了消除这种紧密耦合的现象,可以像下面这样使用arguments.callee。

      function factorial(num){

        if(num <= 1){

          return 1;

        } else {

          return num * arguments.callee(num - 1);

        }

      }

      在这个重写后的factorial()函数体内,没有再引用函数名factorial。这样,无论引用函数时使用的是什么名字,都可以保存正常完成递归调用。

      var trueFactorial=factorial;

      factorial=function(){

        return 0;

      }

      alert(trueFactorial(5));  //120

      alert(factorial(5));        //0

      函数内部另外一个对象是this,其行为与java和C#中的this大致相同。this引用的是函数据以执行操作对象,或则说函数调用语句所处的那个作用域。

      window.color = "red";

      var o = { color : "blue";};

      function sayColor(){

        alert(this.color);

      }

      sayColor();           //red

      o.sayColor = sayColor;

      o.sayColor();      //blue

      上面这个函数sayColor()是在全局作用域中定义的,它引用了this对象。由于在调用函数之前,this的值不确定,因此this可能会在代码执行过程中引用不同的对象。当在全局作用域中调用sayColor()时,this引用的是全局对象window;换句话说,对this.color求值会转换成对window.color求值,于是结果就返回了“red”。而当把这个函数赋值给对象o并调用o.sayColor()时,this引用的对象o,因此对this.color求值会转换成对o.color求值,结果就返回了“blue”;

      备注:函数名字仅仅是一个包含指针的变量而已。因此,即使是在不同的环境中执行,全局的sayColor()函数与o.sayColor()指向的任然是同一个函数。

    四、函数属性和方法

      每个函数包含两个属性:length和prototype。其中,length属性表示函数希望接受的命名参数的个数:

      function sayName(name){

        alert(name);

      }

      function sum(num1,num2){

        reutrn num1 + num2 ;

      }

      function sayHi(){

        alert("hi");

      }

      alert(sayName.length);  //1

      alert(sum.length);        //2

      alert(sayHi.length);      //0

      以上三个函数,每个函数接受的命名参数个数不同。

      每个函数都包含两个非继承而来的方法:apply()和call()。这个两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。首先,apply()方法接收两个参数:一个是在其中运行函数的作用域,另外一个是参数数组。其中,第二个参数可以是Array的实例,也可以使arguments对象。

      function sum(sum1,sun2){

        return sum1 + sum2;

      }

      function callSum1(num1,num2){

        return sum.apply(this,arguments);   //传入arguments对象

      }

      function callSum2(num1,num2){

        return sum.apply(this,[num1,num2]);   //传入数组

      }

      alert(callSum1(10,10)); //20

      alert(callSum2(10,10));//20

      call()方法和 apply()方法的作用相同,他们的区别仅在于接受参数的方法不同。对于call()方法而言,第一个参数是this值没有变法,变法的是其余参数都直接传递给函数。换句话说,在使用call方法时,传递给函数的参数必须一个个的列举出来。

      function sum(sum1,sum2){

        return num1 + num2;

      }

      function callSum(num1,num2){

        return sum.call(this,num1,num2);

      }

      alert(callSum(10,10));  //20

      事实上,传递参数并非apply()和call()真正的用武之地;他们真正强大的地方是能够扩充函数赖以运行的作用域。

      window.color = "red";

      var o = { color : "blue" };

      function sayColor(){

        alert(this.color);

      }

      sayColor();                //red

      sayColor.call(this);    //red

      sayColor.call(window);  //red

      sayColor.call(o);     //blue

  • 相关阅读:
    Ubuntu14.04安装ROS Indigo
    STM32F103移植uCOSIII始终卡在PendSV或Systick处解决办法
    STM32F103移植uCOSIII始终卡在PendSV或Systick处解决办法
    WIN7下PS/2等键盘失灵无法使用的解决办法--实测有效
    WIN7下PS/2等键盘失灵无法使用的解决办法--实测有效
    在altium designer9 等中使用protell99se的如0805,0603等PCB封装库
    在altium designer9 等中使用protell99se的如0805,0603等PCB封装库
    VB将输入文本框的数字分割并按十六进制发送
    Windows 10同步时间的方法
    maven安装cucumber的pom文件设置
  • 原文地址:https://www.cnblogs.com/xchit/p/JavaScript_11.html
Copyright © 2011-2022 走看看