您的位置:首页 > Web前端 > JavaScript

javascript 学习之 数组式的对象(转)

2010-11-14 13:39 543 查看
javascript函数可以用任意多个参数来调用,而不用管函数定义时指定了几个参数。因为函数是弱类型的,没有方法去声明它所期望的参数类型,并且给任何函数传递任何类型的值都是合法的。

可选参数

当调用一个函数时,传递的参数少于声明时的参数。那么额外的参数都将以undefined值来处理。写一些在调用时可以被忽略或者可选的函数也是有用的。要达到这个目的,你必须给那些可能被忽略的参数分配一个合理的值(或指定为null),如:

// 将对象o的所有属性名添加到数组a中,并返回数组a。如果o被忽略,那么先创建,再返回

function copyPropertyNamesToArray(o,a)// 其中,a可以省略

{

if(!a) a=[];// 如果未定义或者为空,就用一个空数组

for(var property in o) a.push(property);

return a;

}

函数定义成这样,就可以非常灵活地调用:

var a=copyPropertyNamesToArray(o);// 将o的所有属性名添加到数组a中

copyPropertyNamesToArray(p,a);// 追加P的属性到数组a中

可以用双竖线操作符||这种符合语言习惯的方式来替换上面函数的第一行代码:

a = a || [];

注意:如果||的第一个参数的值为true或者可以转化为true,此操作将返回第一个参数,否则将返回第二个参数,在这里,如果定义了a并且a不为null,甚至a为empty,都会返回a。否则它将返回一个空数组。

注意在设计函数时,应该确保可选参数排在参数列表的最后。程序员不可能忽略第一个参数而传入第二个。

可变长度的参数列表:参数对象

在函数体内,arguments标识符有着特殊的意义。arguments是一个指向Arguments对象的特殊属性。Arguments对象是一个数组式的对象。他使得传递给函数的参数可以通过数字而不是通过名字来检索。他也定义了callee属性。

尽管在定义函数时指定了固定的参数个数,但是在调用时可以传入任意个参数。Arguments对象可以完全访问到这些参数,甚至是一些或者所有的未命名的。假如你定义了一个只有一个参数x的函数f。而调用时你传入了两个参数。第一个参数可以很容易地通过x或者arguments[0]获得。而第二个参数只能通过argumentts[1]来获取。还有,就像真正的数组一样,arguments有一个length属性指定了它包含的元素个数,因此,在函数f内部,arguments.length的值就是2。

arguments对象在很多时候都是很有用的。下面的例子将向你展示怎样用它来证实用正确数量的参数来调用函数:

function f(x,y,z)

{

// 检查是否传入了正确的参数个数

if(arguments.length !=3)

{throw new Error("function f called with "+arguments.length+"arguments, but it expects 3 arguments.");}



}

arguments对象对于javascript函数来说就有这样一种可能性:这些函数可以被写成接收任意个参数并返回其中的最大值。(和内置函数Math.max()一样,有着同样的工作方式

function()

{

var m=Number.NEGATIVE_INFINITY;

// 循环所有参数,并记录最大的。

for(var i=0;i<arguments.length;i++)

{

if(arguments[i]>m) m=arguments[i];

}

return m;

}

var largest=max(1,2,3,4,54);

注意,像这样的函数不允许无参调用。用arguments[]对象来写一些固定参数后再跟一些可有可无的参数这是完全可行的。

记住,arguments并不是一个真正的数组,它是一个arguments对象。每一个arguments对象定义了有限的元素个数和一个length属性。在技术上来说,它并不是一个数组。可以将它理解为一个有限属性的对象

arguments对象有一个特点。当一个函数有一个已命名的参数时,arguments对象的数组元素是函数参数名的同义词。arguments[]与参数名是调用同一个变量的两种不同方式。用参数名改变参数的值同样会改变arguments[]数组元素的值。反过来也是一样。如:

function(x)

{

print(x); // 显示传入的初始值。

arguments[0]=null;

print(x);// 现在显示null

}

这就证明了arguments并不是一个普通的数组。否则的话,arguments[]和x被初始化具有相同的值,但是一个改变并不会影响到另一个。

callee属性

除了数组元素之外,arguments对象还定义了callee属性用来指向被执行的函数。这个属性很少用到。但它可以允许未命名的函数递归调用自己。如:

function(x)

{

if(x<=1) return 1;

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

}

将对象的属性当作参数

当一个函数需要三个以上的参数时,对调用者来说很难记住参数的正确顺序。为了将程序员从这种每调用一次函数就查一次函数说明书的困境中解救出来,用不计顺序的键值对的形式来传递参数将是一种好的方法。为了使这种想法生效,需要将函数定义成接收一个单独的对象作为参数,然后用户传入一个定义了键值对的object literal。如:

// 从from数组的from_start位置开始复制length个元素到to数组中的to_start位置,这些参数当然很难记

function arraycopy(/*array*/ from,/*index*/ from_start,/*array*/to,/*index*/ to_start,/*integer*/ length){…}

再看看经过改进后的函数

function easycopy(args)

{

arraycopy(args.from,

args.from_start||0,// 注意 这样就支持默认值0

args.to,

args.to_start||0,

args.length);

}

我们这样调用easycopy:

var a=[1,2,3,4];

var b=new Array(4);

easycopy({from:a,to:b,length:4});

参数类型

因为javascript是弱类型的语言,方法的参数不能声明类型也没有对所传值的类型检查。你可以在编写代码时写一些具有描述性名字也可以通过注释来标明参数的类型,就像在arraycopy函数中的一样,对于可选的参数,你可以在注释中添加"optional"这样的单词,当一个方法接受很多个参数时,你可以这样:

function max(/* number…*/){}

javascript中的类型转换是非常自由的。如果你写了一个函数接收一个字符串参数而用其它的类型去调用,你传入的值将会被转换成字符串,所有的原始类型都可以被转换成字符串,所有的对象都有toString()方法,所以这样的错误永远不会发生。

然而并不总是这样,看一下arraycopy函数,它的第一个参数是数组。如果传入的不是数组,那么执行将会失败。这样就需要我们添加代码来检查这样的错误。如果传入了错误的参数,则抛出一个异常来说明一下。这样要比执行失败时再去尝度要好得多。:

// 返回数组(或者类似数组)中所有元素的和

// 元素中的所有元素必须是数字,null 和 undefined将被忽略

function sum(a)

{

if( (a instanceof Array)||(a && typeof a == "object" && "length" in a))// 如果是数组 或者 类似数组的object

{

var total=0;

for(var i=0;i<a.length;i++)

{

var element=a[i];

if(!element) continue;// 忽略null 和 undefined

if(typeof element == "number") total+=element;

else throw new Error("sum(): all array elements must be numbers");

}

return total;

}

else throw new Error ("sum(): argument must be an array");

}

以上的sum就非常严格地检验了传入的参数,同时又可以接收类似数组并且忽略null和undefined元素。

javascript是一种语法非常宽松的弱类型语言,可以写一些对参数的类型和个数都非常宽松的函数。

function flexisum(a)

{

var total=0;

for(var i=0;i<arguments.length;i++)

{

var element=arguments[i];

if(!element) continue; // 忽略null 和 undefined

var n;

switch (typeof element)

{

case "number":

n=element;

break;

case "object":

if(element instanceof Array) n=flexisum.apply(this,element);

else n=element.valueOf();

break;

case "function":

n=element();

break;

case "string":

n=parseFloat(element);

break;

case "boolean":

n=NaN;

break;

}

if(typeof n=="number" && !isNaN(n) total+=n;

else throw new Error("sum(): can't convert "+element+" to number");

}

return total;

}

转自:/article/5774408.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: