本文深入探讨JavaScript中数组与对象的实际应用技巧。内容涵盖数组的多种创建方式、元素增删改(delete与splice的区别)、引用传递机制,以及联合数组(Associative Arrays)与普通数组的本质区别。通过代码示例解析length属性的特殊性、动态属性访问及Function构造函数的应用,帮助开发者避开常见陷阱,提升脚本处理效率。
JavaScript数组与对象的高级应用技巧
使用JavaScript已有三年多,但对部分细节仍不够深入,例如对象和数组的操作仅停留在基础层面。这反映出一种学习上的惰性:仅满足于浅层了解,面对稍复杂的逻辑便缺乏耐心。这种习惯导致学习进度缓慢且基础不牢,遇到复杂问题时容易受阻。
今日在优化脚本并尝试合并数组时遇到障碍,促使我查阅手册并进行测试,从而深入理解相关机制。
数组的创建与动态操作
自JavaScript 1.2版本起,允许使用方括号语法创建数组:
var firstArray = [];
var secondArray = ["red", "green", "blue"];
var thirdArray = [,,,,];
数组创建后仍可动态添加元素:
secondArray[4] = 28;
上述操作的结果是,索引4与索引2之间存在一个空元素(hole)。
最终数组形态类似:["red", "green", "blue",,28]
需注意,数组必须正确初始化。我测试了将数组作为其他数组元素的情况:
var arrArray = [[]];
原设想实现二维数组,但测试发现当索引i>0时,使用arrArray[i][0]访问无效。
仔细分析可知,这实际上仅定义了arrArray[0]为一个空数组,其余元素并未定义,等效于:
var arrArray=[];
arrArray[0]=[];
因此,arrArray[1]未定义,若将其当作数组操作会引发错误。
数组元素的删除与替换
使用delete关键字删除数组元素:
var myColors = ["red", "green", "blue"];
delete myColors[1];
alert("The value of myColors[1] is: " + myColors[1]);
delete操作后,myColors[1]变为undefined,但myColors.length保持不变,数组变为:["red",, "blue"]
使用slice()进行替换或绝对删除数组元素:
var myArray = [1, 2, 3, 4, 5];
myArray.slice(2); // returns [3, 4, 5]
myArray.slice(1, 3); // returns [2, 3]
myArray.slice(-3); // returns [3, 4, 5]
myArray.slice(-3, -1); // returns [3, 4]
myArray.slice(-4, 3); // returns [2, 3]
myArray.slice(3, 1); // returns []
var myArray = [1, 2, 3, 4, 5];
myArray.splice(3,2,''a'',''b'');
// returns 4,5 [1,2,3,''a'',''b'']
myArray.splice(1,1,"in","the","middle");
// returns 2 [1,"in","the","middle",3,''a'',''b'']
数组的引用传递机制
查阅文档得知,数组在传递时是引用传递:
var x = [10, 9, 8];
var y = x;
x[0] = 2;
alert("The value of y's first element is: " + y[0]);
结果如何?
再看此例:
// Declare a reference type (array)
var refType = ["first ", " second", " third"];
// Declare a primitive type (number)
var primType = 10;
// Declare a function taking two arguments, which it will modify
function modifyValues(ref, prim)
{
ref[0] = "changed"; // modify the first argument, an array
prim = prim - 8; // modify the second, a number
}
// Invoke the function
modifyValues(refType, primType);
// Print the value of the reference type
document.writeln("The value of refType is: ", refType+"<
>");
// Print the value of the primitive type
document.writeln("The value of primType is: ", primType);
联合数组与普通数组的区别
测试中发现一个现象:
var arr=[];
arr['a']=1;
arr['b']=2;
alert(arr.length);
弹出的数字是0!
查阅文档后得知,此类数组称为联合数组(Associative Arrays)。arr['a']等同于arr.a,而arr.length等同于arr['length']。在初始化arr(var arr=[];)时,length自动赋值为0。
有人将这种联合数组称为JavaScript的hash table。严格来说,联合数组与普通数组本质上都是对象(JavaScript中一切皆对象),其意义和用法相同。示例如下:
var arr=[];
arr=[1,2,3];
arr.test='test';
alert(arr);
alert(arr[1]);
alert(arr['test']);
var arr={}; arr=[2,3,4]; alert(arr[0]);
var arr={};和var arr=[]都可以写成var arr=function(){};
上述代码表明,下标数组与联合数组相互独立。下标仅作用于下标数组,无法访问联合数组;反之,联合数组不影响length属性。联合数组的键即属性,但下标数组的下标并非属性,arr[0]不等于arr.0,访问arr.0会出错。
在某些场景下,使用arr['a']代替arr.a作为方法调用更有效,因为arr['a']中的'a'可通过变量传入,例如将方法赋给变量:
var d=document,l=links;
此时直接d.l会出错,而使用d[l]可正确执行,通过alert验证即可知晓:
alert(d.l);//脚本错误
alert(d[l]);//显示object
既然数组是具有length属性的对象,是否所有具有length属性的对象都是数组?例如String。测试发现,Firefox可将String当作数组处理,但IE不支持:
var myString = "Hello world";
alert(myString.length);
alert(myString[0]);
数组对象具有独特性,用户自定义对象无法完全模拟:
function myarray(size){
this.length=size;
var x=0;
}
var arr=new myarray(5);
arr[9]=1;
alert(arr);
alert(arr[9]);
alert(arr.length);
原以为Array的length属性仅为普通对象属性,但经上述示例发现,arr的length不再表现为数组length,且arr结构也非普通数组结构。
函数的定义与Function构造函数应用
定义函数/类的方法有多种:
function fName(arguments){
//function body
};
var fName = function(arguments){
//function body
}
var fName = new Function("arguments","/*function body*/");
第三种方法较为有趣,示例如下:
var arr=new Function("var total=0; for (var i=0; i
利用此方法可解析ajax返回的JSON,无需使用低效的eval(未测试其是否比eval快):
假设{b:{c:2}}为返回的json字符串:
var arr=new Function("this.a={b:{c:2}};");
var aa =new arr();
alert(aa.a.b.c);