javascript数组(Array)类型检测-高级
今天遇到一个要完全复制数组的问题,因为用slice和concat进行数组复制的时候,是轻度的复制,当遇见二维数组的时候,就会出问题。
函数如下:
1 function extend (destination,source) { /* 常见的对象复制法 只能复制对象第一层 遇到对象中带对象就蔫了*/ 2 3 for (var attr in source) { 4 destination[attr] = source[attr]; 5 } 6 7 }
因为二维数组的构造造成的,二维数组的时候,第一维是数组引用,第二维是才是实际的内容。依次类推,多维数组最后一维才是真正的值。
对象复制的时候,也会出现这样的问题。
然后看着一个extend()函数解决方案,自己想着先练着写一个函数完全复制的解决函数。
这就遇见了需要检测数据类型,要检测数组中某一位是否还是个数组,看到extend()函数中有句 Object.prototype.toString.call(o);
function extend (goal,source) { /* 完全复制数组函数(也可叫深度复制) */ for (var attr in source) { if (Object.prototype.toString.call(source[attr]).slice(8,-1).toLowerCase() === 'array' ) { goal[attr] = []; arguments.callee(goal[attr],source[attr]); } else { goal[attr] = source[attr]; } } } var arr1 = [[1,2,3],4,5]; var arr2 = []; extend(arr2,arr1); arr1[0][0] = 0; alert([arr1[0][0],arr2[0][0]]); // arr1修改没有影响到arr2,实现了完全复制
下面引用别人的一段,关于Object.prototype.toString()方法的介绍
ECMA-262 写道
Object.prototype.toString( ) When the toString method is called, the following steps are taken:
1. Get the [[Class]] property of this object.
2. Compute a string value by concatenating the three strings “[object “, Result (1), and “]”.
3. Return Result (2)
上面的规范定义了Object.prototype.toString的行为:首先,取得对象的一个内部属性[[Class]],然后依据这个属性,返回一个类似于"[object Array]"的字符串作为结果(看过ECMA标准的应该都知道,[[]]用来表示语言内部用到的、外部不可直接访问的属性,称为“内部属性”)。利用这个方法,再配合call,我们可以取得任何对象的内部属性[[Class]],然后把类型检测转化为字符串比较,以达到我们的目的。还是先来看看在ECMA标准中Array的描述吧:
ECMA-262 写道
new Array([ item0[, item1 [,…]]])
The [[Class]] property of the newly constructed object is set to “Array”.
写一个判断是否为数组的函数
function isArray(o) { /* 检测是否为数组类型 */ return Object.prototype.toString.call(o) === '[object Array]'; }
下面封装把这个检测数据类型方法封装下,并带检测内容
var str = 'str'; var arr = new Array(); var num = 0; var bool = true; var obj = {}; var re = /^[0-9]/; getType(re); // 'regexp' getType(str); // 'string' getType(arr); // 'array' getType(num); // 'number' getType(bool); // 'boolean' getType(obj); // 'object' getType(window.aa); // 'undefined' getType(undefined); // 'undefined' getType(null); // 'null' function getType (o) { /* 检测数据类型函数 */ return Object.prototype.toString.call(o).slice(8,-1).toLowerCase(); }
最后附上实现数组和函数深度复制的函数
function getType (o) { var _t; return ((_t = typeof(o)) == "object" ? o==null && "null" || Object.prototype.toString.call(o).slice(8,-1):_t).toLowerCase(); } function extend (destination,source) { /* 对象和数组深度复制函数 */ for (var attr in source) { if (getType(source[attr]) == 'array' || getType(source[attr]) == 'object') { destination[attr] = getType(source[attr]) === 'array' ? [] : {}; arguments.callee(destination[attr],source[attr]); //继续调用自己 } else { destination[attr] = source[attr]; } }
对了还要介绍下里面用到的slice方法
stringObject.slice(start,end) // 如果传参为负数,则是从字符串末尾开始计算起的位置 str.slice(8,-1) // 即从第8位开始,截取到最后以为,slice方法返回的是截取后的新的字符串
最近学了面向对象,这里也附上面向对象的改写
View Code
1 Array.prototype.extend = function (source) { /* 面向对象--深度复制数组 */ 2 3 for (var attr in source) { 4 5 if (Object.prototype.toString.call(source[attr]).slice(8,-1).toLowerCase() === 'array' ) { 6 this[attr] = []; 7 this[attr].extend(source[attr]); 8 } 9 else { 10 this[attr] = source[attr]; 11 } 12 13 } 14 15 } 16 17 var arr1 = [[1,2,3],4,5]; 18 var arr2 = []; 19 20 arr2.extend(arr1); 21 22 arr1[0][0] = 0; 23 24 alert([arr1[0][0],arr2[0][0]]); // arr1修改没有影响到arr2,实现了完全复制
深度复制的出处找不到了,实在不好意思