JavaScript之引用类型介绍(7)


function sayHi()
{
alert(arguments.length); //2
alert(arguments[0] + ',' + arguments[1]); //hello,world
}
sayHi('hello','world');


  虽然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,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.color求值会转换成对o.color求值,结果就是'blue'。

  函数属性和方法
  因为JavScript中的函数是对象,因此函数也有属性和方法。每个函数都包含两个属性:length和prototype。其中,length属性表示函数希望接收的命名参数的个数。

复制代码 代码如下:


function sayName(name)
{
alert(name);
}
function sayHi()
{
alert('hi');
}

alert(sayName.length);   //1
alert(sayHi.length); //0


  在JavaScript中最耐人寻味的就要数prototype属性了。对于引用类型而言,prototype是保存它们所有实例方法的真正所在。诸如toString()和valueOf()等方法实际上都是保存在prototype名下,只不过是通过各自对象的实例访问罢了。在创建自定义引用类型以及实现继承时,prototype属性的作用是极为重要的(这里就不对prototype属性做详细介绍了)。

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

复制代码 代码如下:


function sum(num1,num2)
{
return num1 + num2;
}
function callSum1(num1,num2)
{
return sum.apply(this,arguments);
}
function callSum2(num1,num2)
{
return sum.apply(this,[num1,num2]);
}
alert(callSum1(10,10)); //20
alert(callSum2(10,10)); //20


  在上面例子中,callSum1()在执行sum()函数时传入了this作为作用域(因为是在全局作用域中调用的,所以传入的就是window对象)和arguments对象。而callSum2同样也调用了sum()函数,但它传入的则是this和一个参数数组。

  call()方法与apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。对于call()方法而言,第一个参数是作用域没有变化,变化的只是其余的参数都是直接传递给函数的。

复制代码 代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wddpzy.html