javascript的Function类型

Function类型

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

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

由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其它变量没有什么不同。

  function sum(num1, num2){
    return num1 + num2;
  }
  alert(sum(10,10));          // 20

  var anotherSum = sum;
  alert(anotherSum(10,10));   // 20

  sum = null;
  alert(anotherSum(10,10));   // 20

声明变量anotherSum,并将其设置为与sum相等(将sum的值赋给anotherSum)。
注意:使用不带圆括号的函数名是访问函数指针,而非调用函数。
此时,anotherSum和sum都指向了同一个函数。即使将sum设置为null,仍然可以正常调用anotherSum()。

作为值的函数

因为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;
  }
  result = callSomeFunction(getGreeting, "Nicholas");
  alert(result);        // "Hello, Nicholas"

函数作为函数的返回值

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

  var data = {{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}};
  data.sort(createComparisonFunction("name"));
  alert(data[0].name);

函数的内部属性

在函数内部,有两个特殊的对象:arguments和this。

arguments属性

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

这样,无论引用函数时使用的什么名字,都可以保证正常完成递归调用。

  var trueFactorial = factorial;

  factorial = function(){
    return 0;
  }
  alert(trueFactorial(5));    // 120
  alert(factorial(5));        // 0

变量trueFactorial获得了factorial的值,实际上是在另一个位置上保存了一个函数的指针。然后,我们又将一个简单地返回0的函数赋值给factorial变量。如果不使用arguments.callee,调用trueFactorial()就会返回0。

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

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

函数的属性

每个函数都包含两个属性:length和prototype。

length属性

表示函数希望接收的命名参数的个数

  function sayHi(){
    alert("hi");
  }
  function sayName(name){
    alert(name);
  }
  function sum(num1, num2){
    return num1 + num2;
  }
  alert(sayHi.length);        // 0
  alert(sayName.length);      // 1
  alert(sum.length);          // 2

prototype属性

对于ECMAScript中的引用类型而言,prototype是保存它们所有实例方法的真正所在。换句话说,诸如toString()和valueOf()
等方法实际上都保存在prototype名下,只不过是通过各自对象的实例访问罢了。在创建自定义引用类型以及继承时,prototype属性的作用是极为重要的。

函数的方法

每个函数都包含两个非继承而来的方法:apply()和call()。这两个方法的用途都是* 在特定的作用域中调用函数,实际上等于设置函数体内this对象的值 *

apply方法

接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中。第二个参数可以是Array的实例,也可以是arguments对象。

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

  function callSum1(num1, num2){
    sum.apply(this, arguments);       // 传入arguments对象
  }
  function callSum2(num1, num2){
    sum.apply(this, [num1, num2]);    // 传入数组
  }

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

callSum1()在执行sum()时传入了this作为this值(因为是在全局作用域中调用的,所以传入的就是window对象)。

call方法

call()和apply()作用相同,区别仅在与接收参数的方式不同。call()的第二个参数必须逐个列举出来。

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

  function callSum(num1, num2){
    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.call(this);    // red
  sayColor.call(window);  // red
  sayColor.call(o);       // blue

使用call()(或apply())来扩充作用域的最大好处,就是对象不需要与方法有任何耦合关系。在前面的代码中,我们先将sayColor()放到了对象o中,然后再通过o来调用它的;而使用call(),就不需要那个多余的步骤了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值