javascript function

  javascript函数是用function定义,也可称为类定义。

  函数的声明:

  1.

  function sum(a, b) {
    return a + b;
  }

  var c = sum(1, 2); // 直接调用函数,sum为函数名。

  2.

  var sum = function(a, b) {

    return a + b;

  }; // 注意,此处要以;结束

  var c = sum(1, 2); // 声明变量sum,并指向该函数的指针

  js里只有函数名代表对函数的指针(可当作变量来使用),而函数名带有()表示对函数的调用。

 

  再看下面例子:

  var tempA = sum;

  alert(tempA(1, 2)); // 可调用,返回为3

  sum = null;

  alert(tempA(1, 3)); // 可调用,返回4

  虽然sum断了函数的引用,但tempA依然保留了指针,所以能调用。

 

  函数没有重载:

  js的函数不同于其他高级语言,没有重载方法,因为函数名代表着对其本身函数的引用指针,如果重载了函数名,则最后下载的函数会覆盖之前所有的函数,例如下:

  function sum(a) {

  }

  function sum(a, b) {

  }

  sum(1); // 此处虽然只有1个参数,但实质调用的是sum(a, b)函数。

  

  函数的内部属性:

  js函数有2个重要的属性,arguments和this,这2个属性每个函数都具有的。arguments表示传入的参数数组,如果空参数则长度为0。

  arguments:

  function sum(a, b) {
    alert(arguments.length);
  }

  sum(); // 输出0

  sum(undefined, undefined); // 输出2

  sum(undefined, 1, 2, 'a'); // 输出4

  另外arguments有一个方法callee,它是调用函数本身,通常用在递归上。具体事例如下图:

  

  function sum(num) {
    if (sum < 0) {

      return;

    }

    sum(--num); // 调用递归
  }

  sum(10); 

  此处递归在不改变函数名情况下是没有问题,但如果需要将sum改为sum2,则函数体也要相应改,代码结构变为紧耦合。JS提供方便的方法callee,可以永远调用自己本身,如下:

  function sum(num) {

    if (sum < 0) {

      return;

    }

    arguments.callee(--num);

  }

  这样无论sum改变什么名称,函数体都不用改变,变为松耦合。

 

  this:

  js的this关键字代表当前执行环境下的本身对象,事例如下:

  function ball() {

    alert(this.color);  

  }

  var color = "red";

  ball(); // 输出red

  因为调用ball是在全局执行环境里,所以即使在ball函数体里this也代表着全局执行环境,相当于window.color。再看下面事例:

  var color = "red";

  var o = new ball(); // 输出undefined

  因为new一个ball,里面函数执行环境变为对象o,再因为o的color未定义,所以输出undefined; 如果要确保在函数体里访问全局执行环境变量,则可用window对象,如下:

  function ball() {

    alert(window.color); // 使用window,无论什么情况都代表访问全局执行环境

  }

  

  函数的预定义参数:

  如果要获取函数定义的参数个数,可以用函数名.length,如果空参数,则返回0.如下:

  function sum(a, b) {

  }

  alert(sum.length); // 输出为2

 

  函数属性和方法:

  JS函数有2个属性是必备的,length和prototype。length表示函数希望接受的参数个数,prototype是函数里所有方法都保存在里面,包括自带的valueOf和toString,只不过是通过各个实例进行访问。

  函数里有2个方法是非继承而来,分别是apply和call,它们的作用都是通过特定的作用域执行函数。

  apply: apply有2个参数,第1个参数是作用域对象,第2个参数是需要传入的参数数组对象,可以传入arguments(也是数组),也可以传入自定义数组

  function sum(a, b) {
    return a + b;
  }

 

  function callSum1(a, b) {

    return sum.apply(this, arguments);    

  }

  function callSum2(a, b) [

    return sum.apply(this, [a, b]);

  }

  

  alert(callSum1(1, 2)); // 输出3

  alert(callSum2(3, 4)); // 输出7

  

  call:跟apply作用一样,唯一的区别是传入的参数略有不同,call传入的是具体每个参数(不是打包成数组)。

  function sum(a, b) {
    return a + b;
  }

  

  function callSum1(a, b) {
    return sum.call(this, a, b);
  }

  alert(callSum1(2, 3)) ; // 输出5 

  apply和call比较:功能完全一样,只是传入参数不同,具体用哪个,看场景,如果传入的参数是已经定义好的数组或者是不可确定的参数个数,当然是apply合适,反之call合适。

 

  对于call还有一个强大的地方,就是扩充作用域,可以指定不同作用域而形成不同的形态。具体看如下代码。

  事例1:

  function pay() {
    alert(this.color);
  }

  var color = "red";

  var o = { color: "red" };

  pay(); // 输出red

  o.pay = pay; //将函数名pay的指针赋于o.pay 

  o.pay(); // 调用函数,实质是调用pay(); 输出blue,因为this作用域已经指向o,所以输出的是o.color

 

  事例2:

  // 代码函数定义沿用事例1

  pay.call(this); // call里参数必须要传入作用域对象,这里的this指向全局执行环境,也就是window对象。输出red

  pay.call(window); // 输出red

  pay.call(o); // 输出blue,传入o作用域

 

  事例1和事例2实现功能一样,但从代码耦合程度则完全不同。事例1多了一段o.pay = pay代码,导致 pay与pay函数紧耦合;事例2只需要调用pay.call并传入对象作用域,即可实现根据不同作用域做不同的事。注:推荐事例2写法。对于上面的事例,也可以用apply,即pay.apply(this); 只不过传入的参数形式不一样。

  

  

 

  

posted @ 2015-08-20 11:54  司马逍遥  阅读(117)  评论(0)    收藏  举报