好几天没有写博客了,这几天忙的事情比较多,大多被公司流程繁琐,开发周期其实很短,现在基本上任务都能提前完成, 可是测试老是拖,用一些条条框框来减慢工作进度,消磨激情,好久没有写样式,发现现在好多IE的小问题,以前习惯性的叫双姐, 现在应该试着自己去解决,提测后只有一个bug也是自己对自己要求变严了,然后就是要帮助同学一起推进项目,遇到很多问题也很经典。
table是一个自适应的布局,给每个td设定一个值,td * length !== table.width这个要让一个表格一直保持自适应还是有点难的
将有关数组的内容总结了一下,新手学习,可能有错,欢迎指正。(都没有人来看我还傻啦吧唧的写这么一句)
##数组 Array 是 JavaScript 中非常常见的类型,数组是有序列表,数组的每一项可以保存任何类型的数据, 数组的大小是可以动态调整的,可以随着数据的添加自动增长以容纳新增数据。
##声明
Array构造器
// 最简单的构造声明
var arr1 = new Array(); // []
// 声明的时候传入一个数字
var arr2 = new Array(20); // [undefined × 20]
// 声明的时候传入参数非一位数字
var arr3 = new Array(1,"a",{}) // [1, "a", Object]
字面量
// 字面量声明
var arr4 = [1,"a",{}] // [1, "a", Object]
注意
// 注意,这样会创建一个包含2或3项的数组
var arr4 = [1,2,] // IE9以下[1, 2, undefined] ;以上 [1, 2]
##读取
读取采用的是 参数名[下标] 的方式读取数组元素。
尽管数组也是Object,但是不能使用参数名.下标的方式。
// 读取数组
arr4[2] // 如果数组中有这个下标的值则返回值,否则返回undefined。
读取时小标类型是String,所以arr4['2'] === arr4[2]。
##Length 属性
length不一定等于数组元素长度。
首先这个属性不是只读,因此,可以通过设置这个值来改变整个数组。且这种方式不会给数组分配更多的空间。
length是小于4294967295的正整数,超过就会溢出。
length没有上界,不会发生越界错误。这个是指原数组长度为10,你给第11个元素赋值,依旧能赋值。
delete一个数组元素,只会将这个位置的空间释放掉,会用一个undefined占位并不会使数组长度减少,并用in判断时为false。
// length 的不正确
var arr1 = [];
arr1[5] = undefined;
console.log(arr1.length); // 6
// length 属性可写
var arr2 = [1,2,3];
arr2.length = 0;
console.log(arr2); // []
arr2.length = 3;
console.log(arr2); // [undefined × 3]
var arr3 = [1,2,3];
delete arr3[0];
0 in arr3 // false
arr3[1] = undefined;
1 in arr3 // true
##循环
枚举:for in可以遍历,但这可能会把原型链中的额外属性循环出来,性能低,且无法保证顺序。
// 枚举
Array.prototype.name = "array"
var arr3 = [1,2,3,4,5]
for(x in arr3){
console.log(x)
}
// 本质还是对象,会遍历数组的所有属性。可能从原型链中得到意外属性。
// 无法保证顺序。
length循环:这也是我们常见的采用遍历数组顺序的方法,但鉴于数组length的动态性,在使用的时候一定要注意,
i < arr4.length;是动态的,且在取的时候一定要注意这个长度是否就是数组的真实长度。
// 循环遍历
Array.prototype.name = "array"
var arr4 = [1,2,3,4,5]
for(var i = 0, arrLength = arr4.length;i < arrLength;i++){
console.log(arr4[i])
}
i++VSi--:这里顺便说一说这两种循环有什么差别,直接跑效果。chrome中的效果。这个是具有浏览器差异性的。
这两种纯遍历,一个是顺序,一个是倒序。这个在使用中一定要注意,已躺坑。
var arr5 = [];
for(var i=0;i<1000000;i++){
arr5.push(i);
}
console.time("aaa");
for(var i=0,arrLen=arr5.length;i<arrLen;i++){
arr5[i];
}
console.timeEnd("aaa");
// aaa: 813.897ms
console.time("aaa");
for(var i=arr5.length;i--;){
arr5[i];
}
console.timeEnd("aaa");
// aaa: 550.553ms
##检测数组类型
instanceof:检测被检测参数是否为Array的实例。这种方式是有局限的。
多个全局执行环境,就会有多个不同版本的Array构造器,
一个环境向另一个环境传入数组的时候,构造器就不同了。
比如嵌入一个iframe,这个时候方法就会失效了。
与全局执行环境有关的构造器如:
window.Array、window.Object、window.String、window.Number
function testArray(value){
return value instanceof Array;
}
typeof + constructor:typeof无法分辨Object、Function、Array。
而constructor不仅存在instanceof的问题,属性易变,不可信赖。
// 属性易变,不可信赖
function F() {};
F.prototype = {};
var f = new F();
f.constructor === F; // false
f.constructor === Object.prototype.constructor // true
F的prototype被对象字面量重写了,重写过后constructor指向了Object
function testArray(value){
return value && typeof value === 'object' && value.constructor === Array;
}
isArray:新的API,支持的浏览器版本有点高。IE9+
function testArray(value){
return Array.isArray(value);
}
Object.prototype.toString:最为完美的类型检测方法。
function typeChecking(arg){
var type = typeof(arg);
if(type !== "object"){
return type;
}else{
return Object.prototype.toString.call(arg).slice(8,-1);
}
}
##Array值的转换
toString
var arr1 = [1,"song"];
// toString
console.log(arr1.toString()); // 1,song
// toLocaleString
console.log(arr1.toLocaleString()); // 1,song
// valueOf
console.log(arr1.valueOf()); // [1,"song"]
alert(arr1.valueOf()) // 1,song
arr1.valueOf() === arr1
// join
console.log(arr1.join(",")); // 1,song
tostring和toLocalString的区别:用toString是传统字符串,toLocaleString是本地环境字符串。
使用场景更多的是toString,特别是对服务器端处理字符串。
如果返回的是时间类型的数据,用于给用户看的数据更多推荐使用LocaleString()。
(new Date()).toString();
(new Date()).toLocaleString();
参数改变:
arr1 = [1,"song",undefined,null,[1]];
// toString
console.log(arr1.toString()); // 1,song,,,1
// toLocaleString
console.log(arr1.toLocaleString()); // 1,song,,,1
// valueOf
console.log(arr1.valueOf()); // [1,"song",undefined,null,Array[1]]
alert(arr1.valueOf()) // 1,song,,,1
arr1.valueOf() === arr1
// join
console.log(arr1.join(",")); // 1,song,,,1
如果改写我们现有的方法:
var obj1 = {
toString: function(){
console.log("l am toString obj1");
},
toLocaleString: function(){
console.log("l am toLocaleString obj1");
},
valueOf: function(){
console.log("l am valueOf obj1");
},
join: function(){
console.log("l am join obj1");
}
},
obj2 = {
toString: function(){
console.log("l am toString obj2");
},
toLocaleString: function(){
console.log("l am toLocaleString obj2");
},
valueOf: function(){
console.log("l am valueOf obj2");
},
join: function(){
console.log("l am join obj2");
}
},
arr2 = [obj1, obj2];
// toString
console.log(arr2.toString());
// l am toString obj1
// l am toString obj2
// undefined,undefined
// toLocaleString
console.log(arr2.toLocaleString());
// l am toLocaleString obj1
// l am toLocaleString obj2
// undefined,undefined
// valueOf
console.log(arr2.valueOf());
// [Object, Object]
alert(arr2.valueOf());
// l am toString obj1
// l am toString obj2
// undefined,undefined
// alert与console 不同,alert只接受字符串,所以会调用toString方法
// join
console.log(arr2.join(","));
// l am toString obj1
// l am toString obj2
// undefined,undefined
// join 其实会触发调用toString方法
// 多维数组只会作用于一层。
var arr = [[1,2,3,[7,8,9]],[4,5,6]];
arr.join("|");
// "1,2,3,7,8,9|4,5,6"
##API
push
/**
* @method push
* 向数组的队尾增加多个元素
*
* @param {All} 多个参数用逗号隔开,支持所有类型参数
* @return {Number} 新数组的长度,会改变源数组
*/
var a = ['a','b','c'],
b = ['x','y','z'],
c = a.push(b,true); // a = ["a", "b", "c", ["x", "y", "z"], true] c = 5
pop
/**
* @method pop
* 移除数组最后一个元素
*
* @return {All} 返回被移除的元素,会改变源数组
*/
var a = ['a','b','c'],
b = a.pop(); // a = ["a", "b"] b = "c"
<!-- 也可以使用 a.length -= 1,但返回值为新数组长度-->
shift
/**
* @method shift
* 移除数组第一个元素
*
* @return {All} 返回被移除的元素,源数组会改变
*/
var a = ['a','b','c'],
b = a.shift(); // a = ["b", "c"] b = "a"
unshift
/**
* @method unshift
* 向数组的队尾增加多个元素
*
* @param {All} 多个参数用逗号隔开,支持所有类型参数
* @return {Array} 新数组的长度,会改变源数组
*/
var a = ['a','b','c'],
b = ['x','y','z'],
c = a.unshift(b,true); // a = [["x", "y", "z"], true, "a", "b", "c"] c = 5
concat
/**
* @method concat
* 拼接两个数组,浅复制,效率比slice略高
*
* @param {All} 多个参数用逗号隔开,支持所有类型参数
* @return {Array} 新数组的长度,不会改变源数组
*/
var a = ['a','b','c'],
b = ['x','y','z'],
c = a.concat(b,true); // c = ["a", "b", "c", "x", "y", "z", true] a还是a
// push可用API实现
Array.prototype.push = function(){
this.splice.apply(this,[this.length,0].concat(Array.prototype.slice.apply(arguments)));
return this.length;
}
reverse
/**
* @method reverse
* 反转 array 里的元素顺序
*
* @return {Array} 返回新的顺序的数组,会改变源数组
*/
var a = ['a','b','c'],
b = a.reverse(); // a = ["c", "b", "a"] b = ["c", "b", "a"]
sort
/**
* @method sort
* 给数组排序
*
* @param {function} 排序方法,会自动传入两个参数,对比的
* @return {Array} 返回新的顺序的数组,会改变源数组
*/
var a = [1,24,13,23,41],
b = a.sort(function(x,y){
console.log(x,y)
}); // a = [1, 13, 23, 24, 41] b = [1, 13, 23, 24, 41]
// sort()在排序的时候会把每个元素都调用toString转型再比较得到的字符串。
indexof
/**
* @method indexof
* 默认从0位开始索引 IE9+
*
* @param {All} 被搜索的参数
* @param {number} 索引的起点位置
* @return {Number} 被搜索的参数所在的位置,以0开始记位,找到就直接返回,没有找到则返回-1
*/
var numbers = [1,2,3,4,5,4,3,2,1];
console.log(numbers.indexOf(4)); // 3
console.log(numbers.indexOf(4,4)); // 5
lastIndexOf
/**
* @method lastIndexOf
* 默认从队尾位开始索引 IE9+
*
* @param {All} 被搜索的参数
* @param {number} 索引的起点位置
* @return {Number} 被搜索的参数所在的位置,以0开始记位,找到就直接返回,没有找到则返回-1
*/
var numbers = [1,2,3,4,5,4,3,2,1];
console.log(numbers.lastIndexOf(4)); // 5
console.log(numbers.lastIndexOf(4,4)); // 3
// 对象
var person = {name:"karyn"},
people = [{name:"karyn"}],
peoples = [people];
console.log(peoples.indexOf(person)) // -1
console.log(peoples.indexOf(people)) // 0
slice
/**
* @method slice
* 截取数组
*
* @param {Number} 截取数组的起点位置,从0开始计算
* @param {Number} 截取数组的重点位置,最长为length长度
* @return {Array} 最终被截取出来的数组,不会改变源数组
*/
var numbers = [1,2,3,4,5,4,3,2,1];
console.log(numbers.slice(0,3)) // 初始位置小于终点位置,且都为正数
console.log(numbers.slice(0,-1)) // 两个参数任意为负数,都先用该数加上 length,再比较
console.log(numbers.slice(0,0)) // 初始位置大于等于终点位置,返回空数组
console.log(numbers.slice()) // 浅复制
splice
/**
* @method splice
* 可用于对数组进行增、删、改
*
* @param {Number} 起始位置,从0位置开始
* @param {Number} 操作字符的长度
* @param {All} 需要增加的字符串
* @return {Array} 被删除的元素,会改变源数据
*/
var numbers = [1,2,3,4,5,4,3,2,1];
console.log(numbers.splice(0,0,"000")) // 从头部开始新增
console.log(numbers.splice(numbers.length,1,"000")) // 从尾部开始新增
console.log(numbers.splice(0,1)) // 删除
console.log(numbers.splice(0,2,10,11)) // 替换
##新增API
新增API都需要运行,然后一眼就能看出效果。需要注意的地方都写在return里了
forEach
/**
* @method forEach
* 遍历数组
*
* @param {Number} 多个参数用逗号隔开,支持所有类型参数
* @param {Number} 数组的下标
* @param {Array} 数组本身
* 无 return 值,不能停止遍历,
*/
var arr1 = [1,24,13,23,41],
arr2 = arr1.forEach(function( item, index, array){
console.log(item, index, array);
});
map
/**
* @method map
* 迭代遍历数组
*
* @param {Number} 多个参数用逗号隔开,支持所有类型参数
* @param {Number} 数组的下标
* @param {Array} 数组本身
* @return {all} return 的数值会生成新的数组。
*/
var arr1 = [1,24,13,23,41],
arr2 = arr1.map(function( item, index, array){
console.log(item, index, array);
return item - 1;
});
some
/**
* @method some
* 迭代遍历数组
*
* @param {Number} 多个参数用逗号隔开,支持所有类型参数
* @param {Number} 数组的下标
* @param {Array} 数组本身
* @return {Boolean} false 会继续,true 就会推出
*/
var arr1 = [1,24,13,23,41];
arr2 = arr1.some(function( item, index, array){
console.log(item, index, array);
return item < 10;
});
every
/**
* @method every
* 迭代遍历数组
*
* @param {Number} 多个参数用逗号隔开,支持所有类型参数
* @param {Number} 数组的下标
* @param {Array} 数组本身
* @return {Boolean} true会继续遍历,false会退出
*/
var arr1 = [1,24,13,23,41];
arr2 = arr1.every(function( item, index, array){
console.log(item, index, array);
return item < 10;
});
filter
/**
* @method filter
* 迭代遍历数组
*
* @param {Number} 多个参数用逗号隔开,支持所有类型参数
* @param {Number} 数组的下标
* @param {Array} 数组本身
* @return {Boolean} true会将该item 保存在新数组里
*/
var arr1 = [1,24,13,23,41];
arr2 = arr1.filter(function( item, index, array){
console.log(item, index, array);
return item < 10;
});
reduce
/**
* @method reduce
* 迭代从左往右遍历数组
*
* @param {Number} 多个参数用逗号隔开,支持所有类型参数
* @param {Number} 数组的下标
* @param {Array} 数组本身
* @return {All} 递归数组里所有的元素,可对元素进行操作,不会影响元数据,最终return 的是迭代return的结果
*/
var arr1 = [1,24,13,23,41];
arr2 = arr1.reduce(function( previous, current, index, array){
console.log(previous, current, index, array);
return previous + current;
});
reduceRight
/**
* @method reduceRight
* 迭代从右往左遍历数组
*
* @param {Number} 多个参数用逗号隔开,支持所有类型参数
* @param {Number} 数组的下标
* @param {Array} 数组本身
* @return {Boolean} 递归数组里所有的元素,可对元素进行操作,不会影响元数据,最终return 的是迭代return的结果
*/
var arr1 = [1,24,13,23,41];
arr2 = arr1.reduceRight(function( previous, current, index, array){
console.log(previous, current, index, array);
return previous + current;
});
以上是所有对数组的理解,特别是对length的理解,删除数组的方式delete和splice各有各的好处,
前者可以保留索引,而后者可以动态变更数组长度。