《深入理解JavaScript》—— 数组
学习是一种循序渐进的过程,关于上一节第3和第4我暂时是不能太理解,所以就算写出来,意义也不是太大,先空着。坑太多,未来随着学习的深入,我会一个一个填的。
数组,什么是数组?数组是索引(从零开始的自然数)到任意值的映射。这些值(映射的范围)称为数组的元素。创建数组最简便的方式就是使用数组字面量。
(1) 多维数组
如果你需要多个维度的元素,必须嵌套数组。当你创建这样的嵌套数组是,最内层的数组可以根据需要添加。但如果想要直接访问这些元素,你至少需要创建外层的数组。在下面的例子中,创建了一个3x3的井字形矩阵。这个矩阵完全用数据填充(而不是需要时增加行数)
var rows = []; for ( var rowCount = 0; rowCount < 3; rowCount++ ) { rows[rowCount] = []; for ( var colCount = 0; colCount < 3; colCount++ ) { rows[rowCount][colCount] = '.'; } } rows[0][2] = 'X'; rows.forEach(function (row) { console.log ( row.join(' ') ); }); // . . X // . . . // . . .
(2) 数组索引
在使用索引时,你必须明白:
1. 索引i是数字,范围是0≤i≤2^23-1
2. 最大长度是2^23-1
而在这个范围之外的索引被视为普通的属性键。他们不会作为数组元素呈现,也不影响length属性。
(3) 数组原型方法
1. 添加和删除元素(破坏性地)
① Array.prototype.shift(): 移除索引0出的元素并返回该元素。随后的元素索引减1。
② Array.prototype.unshift(): 在数组最前面增加给定元素,返回新数组的长度。
③ Array.prototype. pop(): 移除数组最后的元素并返回该元素。
④ Array.prototype.push(): 在数组的尾部增加给定元素,返回新数组的长度。
⑤ Array.prototype.splice(start,deleteCount?,elem1?,elem2?...): 从索引start开始,移除deleteCount个元素,并插入给定的元素。换句话说,用elem1、elem2等元素替换了索引start开始的deleteCount个元素。该方法返回被移除的元素。
注:
1. start可以为负数,这种情况下,start与数组的length相加来确定起始位置。因此-1指向最后的元素,以此类推。
2. deleteCount是可选的。如果省略(连同后面的参数),那么在start索引后的所有元素都会被移除。
2. 排序和颠倒元素顺序(破坏地)
① Array.prototype.reverse(): 颠倒数组中的元素顺序,并返回指向原(修改后的)数组的引用。
② Array.prototype.sort(): 数组排序,并返回排序后的数组。
注:请记住,排序是通过吧元素转化为字符串再对值进行比较,这意味着数字不是按照数值进行排序的!
3. 合并、切分和连接(非破坏性地)
① Array.prototype.concat(arr1?,arr2?,...): 创建一个新数组,其中包括接受者的所有元素,其次是数组arr1的所有元素,以此类推。如果其中一个参数不是数组,那么它作为元素添加到结果中。
var arr =[1,2,3]; arr.concat('a',[4,5]); // [1,2,3,"a",4,5]
② Array.prototype.slice(begin?,end?): 把数组从begin开始到end(不包括end)的元素复制到新的数组中。
注: 如果缺少end,则使用数组长度;如果两个索引都缺少,那么复制整个数组。
③ Array.prototype.join(separator?): 通过对所有数组元素应用toString()创建字符串,并用separator连接字符串。如果缺少separator,默认用‘,’。
4. 值的查找(非破坏性地)
① Array.prototype.indexOf(searchValue,startIndex?): 从数组的startIndex开始,查找searchValue。这个方法返回第一次出现searchValue的索引,如果没有找到,则返回-1.如果startIndex四负数,则加上数组长度;如果缺少startIndex,则查找整个数组。
② Array.prototype.lastIndexOf(searchValue,startIndex?) : 与上述方法一样,不过是反向查找searchValue。
5. 迭代(非破坏性地)
迭代方法使用一个函数遍历数组。
1. 检测方法
① Array.propotype.forEach(callback,thisValue?): 遍历数组中的元素。
var arr = [1,2,3,4,5]; arr.forEach(function (elem) { console.log(elem); }); // 1 // 2 // 3 // 4 // 5
② Array.propotype.every(callback,thisValue?): 如果对每个元素,回调函数都返回true,则返回true。一旦回调函数返回false,则停止迭代。注意,如果没有返回值会导致隐式返回undefined,而every()解释为false。every()相当于全称量词。
示例:检测数组中是否每个元素都是偶数。
function isEven( x ) { return x % 2 === 0; } var a = [2,4,6].every(isEven); var b = [2,4,5].every(isEven); console.log(a); // true console.log(b); // false
注:如果数组是空的,那么结果是true(且不调用callback)。
var c = [].every(isEven); console.log(c); // true
③ Array.propotype.some(callback,thisValue?): 如果回调函数至少有一个元素返回true,则返回true。一旦回调函数返回true,则停止迭代。注意,如果没有返回值会导致隐式返回undefined,而some()解释为false。some()相当于存在量词。
示例:检测数组中是否有偶数。
function isEven( x ) { return x % 2 === 0; } var a = [1,3,5].some(isEven); var b = [1,4,5].some(isEven); console.log(a); // false console.log(b); // true
注: 如果数组是空的,那么结果是false(且不调用callback)。
注: forEach()的潜在缺陷是不支持break或类似于提前终止循环的处理。如果你需要这么做,那么你可以使用some()。
function breaAtEmptyString( strArr ) { strArr.some(function (elem) { if ( elem.length === 0 ) { return true; } console.log(elem); }); }
如果发生中断,some()返回true,否则返回false。这样你就可以根据是否需要成功完成迭代来使用不同的方法。
2. 转化方法
转化方法接受一个输入数组,产生一个输出数组,回调函数控制如何产生输出。
① Array.propotype.map(callback,thisValue?): 输出数组的每个元素是对输入元素应用callback后的结果。例如:
var a = [1,2,3]; var b = a.map(function (x) { return x * 2; }); console.log(b); // [2,4,6]
② Array.propotype.filter(callback,thisValue?):输出数组只包含callback返回为true的输入元素。例如:
var a = [1,0,3,0,0,6,8]; var b = a.filter(function (x) { return x !== 0; }); console.log(b); // [1,3,6,8]
3. 归约函数
① Array.propotype.reduce(callback,initialValue?): 从左到右进行迭代,并按照之前描述的调用回调函数。这个方法的结果是由回调函数返回的最后的值。
例如:计算所有数组的元素的和:
var a = [1,2,3,4]; var b = a.reduce(function (x,y) { return x + y; }); console.log(b); // 10
② Array.propotype.reduceRight(callback,initialValue?): 工作原理与reduce()相同,不过是从右到左遍历。