数组html
数组是值的有序集合,每一个值叫作一个元素,而每一个元素在数组中有一个位置,以数字表示,称为索引。前端
JavaScript数组的索引是基于零的32位数值,第一个元素索引为0,数组最大能容纳4294967295(即2^32-1)个元素。web
JavaScript数组是动态的,根据须要它们会增加或缩减,而且在建立数组时无需声明一个固定的大小或者在数组大小变化时无需从新分配空间。编程
JavaScript数组多是稀疏的,数组元素的索引不必定要连续的,它们之间能够有空缺。设计模式
每一个JavaScript数组都有一个length属性,针对非稀疏数组,该属性就是数组元素的个数。针对稀疏数组,length比全部元素的索引都要大。数组
建立数组 一、最简单的方法是使用数组直接量(字面量)建立数组。浏览器
var empty = []; //没有元素的数组
var arr = [1.1, true, "a",]; //3个不一样类型的元素和结尾的逗号
复制代码
数组直接量中的值也不必定必须是常量,它们能够是任意的表达式:缓存
var number = 1;
var list = [number, number+1, number+2];
复制代码
若是省略数组直接量中的某个值,省略的元素用empty表示(就是没有这个元素),访问的话会返回undefined。bash
var count = [1,,3]; // 数组打印出来是(3) [1, empty, 3], count[1] === undefined是true。
var undefs = [,,]; // 数组直接量语法容许有可选的结尾的逗号,顾[,,]只有两个元素而非三个,undefs.length 是 2
复制代码
二、构造函数Array()建立数组 调用时没有参数,等同于[],建立一个没有任何元素的空数组数据结构
var arr = new Array();
复制代码
调用时有一个数值参数,它指定长度
var arr = new Array(10) // (10) [empty × 10]
复制代码
显式指定两个或者多个数组元素或者数组元素的一个非数值元素
var arr = new Array(1,2,3,"one");
复制代码
三、ES6的一些方法 (1)Array.of() 返回由全部参数组成的数组,不考虑参数的数量或类型,若是没有参数就返回一个空数组 (ES6新增)
参数:
elementN 任意个参数,将按顺序成为返回数组中的元素。
注意:
of() 能够解决上述构造器因参数个数不一样,致使的行为有差别的问题(参数只有一个数值时,构造函数会把它当成数组的长度)。
Array.of(1,2,3); // [1,2,3]
Array.of(1,{a:1},null,undefined) // [1, {a:1}, null, undefined]
// 只有一个数值参数时
let B = new Array(3); // (3) [empty × 3]
let C = Array.of(3); // [3]
复制代码
返回值: 新的 Array 实例。
(2)Array.from()从一个类数组或可迭代对象中建立一个新的数组 (ES6新增)
参数:
第一个参数:想要转换成数组的类数组或可迭代对象 第二个参数(可选):回调函数,相似数组的map方法,对每一个元素进行处理,将处理后的值放入返回的数组。 第三个参数(可选):绑定回调函数的this对象
// 有length属性的类数组
Array.from({length:5},(v,i) => i) //[0, 1, 2, 3, 4]
// 部署了Iterator接口的数据结构 好比:字符串、Set、NodeList对象
Array.from('hello') // ['h','e','l','l','o']
Array.from(new Set(['a','b'])) // ['a','b']
// 传入一个数组生成的是一个新的数组,引用不一样,修改新数组不会改变原数组
let arr1 = [1,2,3]
let arr2 = Array.from(arr);
arr2[1] = 4;
console.log(arr1,arr2)
//[1, 2, 3] [1, 4, 3]
复制代码
返回值: 新的 Array 实例。
知识点
//数组合并去重
function combine(){
let arr = [].concat.apply([], arguments); //没有去重复的新数组,以后用Set数据结构的特性来去重
return Array.from(new Set(arr));
}
var m = [1, 2, 2], n = [2,3,3];
console.log(combine(m,n));
复制代码
数组方法
一、会改变原数组的方法
let arr = [1,2,3];
let length = arr.push('末尾1','末尾2'); // 返回数组长度
console.log(arr,length)
// [1, 2, 3, "末尾1", "末尾2"] 5
复制代码
返回值: 数组的长度
//组合使用push()和pop()可以用JavaScript数组实现先进后出的栈
let stack = [];
stack.push(1,2) // 返回长度2,这时stack的值是[1,2]
stack.pop() // 返回删除的值2,这时stack的值是[1]
复制代码
返回值: 从数组中删除的元素(当数组为空时返回undefined)。
let arr = [3,4,5];
let length = arr.unshift(1,2); // 返回长度是5
console.log(arr, length)
//[1, 2, 3, 4, 5] 5
复制代码
注意: 当调用unshift()添加多个参数时,参数时一次性插入的,而非一次一个地插入。就像是上例添加1和2,他们插入到数组中的顺序跟参数列表中的顺序一致,而不是[2,1,3,4,5]。
返回值: 返回数组新的长度。
let arr = [1,2,3];
let item = arr.shift(); // 返回删除的值1
console.log(arr, item)
// [2, 3] 1
复制代码
返回值: 从数组中删除的元素; 若是数组为空则返回undefined 。
参数:
start
指定修改的开始位置(从0计数)。若是超出了数组的长度,则从数组末尾开始添加内容;若是是负值,则表示从数组末位开始的第几位(从-1计数);若只使用start参数而不使用deleteCount、item,如:array.splice(start) ,表示删除[start,end]的元素。
deleteCount (可选)
整数,表示要移除的数组元素的个数。若是 deleteCount 是 0,则不移除元素。这种状况下,至少应添加一个新元素。若是 deleteCount 大于start 以后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。 若是deleteCount被省略,则其至关于(arr.length - start)。
item1, item2, ... (可选)
要添加进数组的元素,从start 位置开始。若是不指定,则 splice() 将只删除数组元素。
返回值: 由被删除的元素组成的一个数组。若是只删除了一个元素,则返回只包含一个元素的数组。若是没有删除元素,则返回空数组。
// start不超过数组长度(如下操做是连续的)
let arr = [1,2,3,4,5];
arr.splice(2) // arr是[1,2],返回值是[3,4,5]
arr.splice(1,1) // arr是[1],返回值是[2]
arr.splice(0,3) // arr是[],返回值是[1],由于此时数组从第0位开始不够3位,因此是删除从0开始到最后的全部元素。
// start大于数组长度(如下操做是连续的)
let arr = [1,2,3,4,5];
arr.splice(5) // arr是[1,2,3,4,5],返回值是[]
arr.splice(5,3,6) // arr是[1,2,3,4,5,6],返回值是[]
arr.splice(5,3,7) // arr是[1,2,3,4,5,7] 返回值是[6]
// start是负数(如下操做是连续的)
let arr = [1,2,3,4,5];
arr.splice(-3,2); // arr是[1,2,5], 返回值是[3,4]
arr.splice(-4); // arr是[],返回值是[1,2,5]
// 插入数组时,是插入数组自己,而不是数组元素
let arr = [1,4,5];
arr.splice(1,0,[2,3]) // arr是[1,[2,3],4,5],返回值是[]
复制代码
compareFunction (可选) 用来指定按某种顺序进行排列的函数。若是省略,元素按照转换为的字符串的各个字符的Unicode位点进行排序。 若是指明了 compareFunction ,那么数组会按照调用该函数的返回值排序。即 a 和 b 是两个将要被比较的元素:
若是 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 以前; 若是 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。备注: ECMAScript 标准并不保证这一行为,并且也不是全部浏览器都会遵照(例如 Mozilla 在 2003 年以前的版本); 若是 compareFunction(a, b) 大于 0 , b 会被排列到 a 以前。 compareFunction(a, b) 必须老是对相同的输入返回相同的比较结果,不然排序的结果将是不肯定的。
var stringArray = ["Blue", "Humpback", "Beluga"];
var numberArray = [40, 1, 5, 200];
function compareNumbers(a, b){
return a - b;
}
console.log('stringArray:' + stringArray.join());
console.log('Sorted:' + stringArray.sort());
console.log('numberArray:' + numberArray.join());
// 没有使用比较函数时,数字并不会按照咱们设想的那样排序
console.log('Sorted without a compare function:'+ numberArray.sort());
console.log('Sorted with compareNumbers:'+ numberArray.sort(compareNumbers));
//打印以下
// stringArray: Blue,Humpback,Beluga
// Sorted: Beluga,Blue,Humpback
// numberArray: 40,1,5,200
// Sorted without a compare function: 1,200,40,5
// Sorted with compareNumbers: 1,5,40,200
复制代码
返回值: 返回排序后的数组。原数组已经被排序后的数组代替。
let arr = [1,2,3];
arr.reverse() // arr是[3,2,1],返回值是[3,2,1]
复制代码
返回值: 返回顺序颠倒后的数组。原数组已经被排序后的数组代替。
参数:
target
0 为基底的索引,复制序列到该位置。若是是负数,target 将从末尾开始计算。
若是 target 大于等于 arr.length,将会不发生拷贝。若是 target 在 start 以后,复制的序列将被修改以符合 arr.length。
start
0 为基底的索引,开始复制元素的起始位置。若是是负数,start 将从末尾开始计算。
若是 start 被忽略,copyWithin 将会从0开始复制。
end
0 为基底的索引,开始复制元素的结束位置。copyWithin 将会拷贝到该位置,但不包括 end 这个位置的元素。若是是负数, end 将从末尾开始计算。
若是 end 被忽略,copyWithin 将会复制到 arr.length。
返回值: 改变了的数组。
[1, 2, 3, 4, 5].copyWithin(-2);
// [1, 2, 3, 1, 2]
[1, 2, 3, 4, 5].copyWithin(0, 3);
// [4, 5, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(0, 3, 4);
// [4, 2, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(-2, -3, -1);
// [1, 2, 3, 3, 4]
// copyWithin 函数是设计为通用的,其不要求其 this 值必须是一个数组对象。
[].copyWithin.call({length: 5, 3: 1}, 0, 3);
// {0: 1, 3: 1, length: 5}
复制代码
参数:
value 用来填充数组元素的值。
start (可选) 起始索引,默认值为0。
end (可选) 终止索引,默认值为 this.length。
若是 start 是个负数, 则开始索引会被自动计算成为 length+start, 其中 length 是 this 对象的 length 属性值. 若是 end 是个负数, 则结束索引会被自动计算成为 length+end。
返回值: 修改后的数组
[1, 2, 3].fill(4); // [4, 4, 4]
[1, 2, 3].fill(4, 1); // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2); // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 3); // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2); // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 5); // [1, 2, 3]
Array(3).fill(4); // [4, 4, 4]
//fill 方法故意被设计成通用方法, 该方法不要求 this 是数组对象。
[].fill.call({ length: 3 }, 4); // {0: 4, 1: 4, 2: 4, length: 3}
复制代码
二、不改变原数组的方法
begin (可选)
从该索引处开始提取原数组中的元素(从0开始)。
若是该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2)表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。
若是省略 begin,则 slice 从索引 0 开始。
end (可选)
在该索引处结束提取原数组元素(从0开始)。
slice会提取原数组中索引从 begin 到 end 的全部元素(包含begin,但不包含end)。 slice(1,4) 提取原数组中的第二个元素开始直到第四个元素的全部元素 (索引为 1, 2, 3的元素)。
若是该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。 slice(-2,-1)表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)。
若是 end 被省略,则slice 会一直提取到原数组末尾。
若是 end 大于数组长度,slice 也会一直提取到原数组末尾。
返回值: 一个含有提取元素的新数组
let arr = [1,2,3,4,5];
let arr1 = arr.slice(1,3); // arr是[1,2,3,4,5], arr1是[2,3]
let arr2 = arr.slice(-2,-1); // arr是[1,2,3,4,5], arr2是[4]
// 开始位置在结束位置后面,获得的数组是空
let arr3 = arr.slice(-2, -3); // arr是[1,2,3,4,5], arr3是[]
let arr4 = arr.slice(2, 1); // arr是[1,2,3,4,5], arr4是[]
//若是元素是个对象引用 (不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。若是被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。
let arr = [{name: 'xiaoming'}];
let arr1 = arr.slice(); // arr是[{name: xiaoming}],arr1是[{name: 'xiaoming'}]
arr1[0].name = 'xiaogang'; // arr是[{name: 'xiaogang'}],arr1是[{name: 'xiaogang'}]
// 对于字符串、数字及布尔值来讲(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另外一个数组。
let arr = [1,2,3];
let arr1 = arr.slice(); // arr是[1,2,3],arr1是[1,2,3]
arr1[1] = "two"; // arr是[1,2,3],arr1是[1,"two",3]
// 固然,若是向两个数组任一中添加了新元素(简单或者引用类型),则另外一个不会受到影响。
复制代码
separator (可选) 指定一个字符串来分隔数组的每一个元素。 若是有(separator),将分隔符转换为字符串。 若是省略(),数组元素用逗号分隔。默认为 ","。 若是separator是空字符串(""),则全部元素之间都没有任何字符。
let num = [1,2,3];
let str1 = num.join(); // 1,2,3
let str2 = num.join(', ') // 1, 2, 3
let str3 = num.join('') // 123
//全部的数组元素被转换成字符串,再用一个分隔符将这些字符串链接起来。若是元素是undefined 或者null, 则会转化成空字符串。
let num = [1,null,3];
let str1 = num.join(); // 1,,3
//若是数组中的元素是数组,会将里面的数组也调用join()
let num = [[1,2],3];
let str1 = num.join('-'); // 1,2-3
// 若是数组中的元素是对象,对象会被转为[object Object]字符串
let num = [{num: 1},2,3];
let str1 = num.join('-'); // [object Object]-2-3
复制代码
返回值: 一个全部数组元素链接的字符串。若是 arr.length 为0,则返回空字符串
知识点
// 扁平化简单的二维数组
const arr = [11, [22, 33], [44, 55], 66];
const flatArr = arr.join().split(','); // ["11", "22", "33", "44", "55", "66"]
复制代码
[1,2,3].toString(); // 1,2,3
[1,[2,'c']].toString(); //1,2,c
// 以上与不使用任何参数调用join()方法返回的字符串是同样的。
// 如下的这个例子要跟下面的toLocaleString对照看
[{a:1},1,new Date()].toString() //"[object Object],1,Sat Jul 07 2018 18:43:45 GMT+0800 (中国标准时间)"
复制代码
注意: 当数组和字符串操做的时候,js 会调用这个方法将数组自动转换成字符串
[1,2,3]+'abc' //1,2,3abc
复制代码
返回值: 返回一个字符串表示数组中的元素
知识点
// 扁平化简单的二维数组
const arr = [11, [22, 33], [44, 55], 66];
const flatArr = arr.toString().split(','); // ["11", "22", "33", "44", "55", "66"]
复制代码
locales (可选) 带有BCP 47语言标记的字符串或字符串数组
options (可选) 一个可配置属性的对象
//数组中的元素将会使用各自的 toLocaleString 方法:
// Object: Object.prototype.toLocaleString()
// Number: Number.prototype.toLocaleString()
// Date: Date.prototype.toLocaleString()
let prices = ['¥7', 500, 8123, 12];
// 不带参数
prices.toLocaleString(); // "¥7,500,8,123,12"
//带参数
prices.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' }); // "¥7,500,8,123,12"
//MDN上的举例中说是 "¥7,¥500,¥8,123,¥12",在浏览器和Node中验证了返回的都是 "¥7,500,8,123,12" 啊!
// 如下的这个例子要跟上面的toString对照看
[{a:1},1,new Date()].toLocaleString() //"[object Object],1,2018/7/7 下午6:45:00"
复制代码
返回值: 表示数组元素的字符串。
参数:
valueN (可选) 将(多个)数组和/或值链接成新数组。
[1,2,3].concat([4,5,6],[7,8,9]) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
['a','b','c'].concat(1,[2,3],[[4,5]]) // ["a", "b", "c", 1, 2, 3, [4,5]]
// concat方法不会改变this或任何做为参数提供的数组,而是返回一个浅拷贝,因此原始数组和新数组都引用相同的对象。 若是引用的对象被修改,新数组和原始数组都会变。
let obj = {a: 1};
let arr1 = [2,obj];
let arr2 = [1].concat(arr1);
console.log(arr1,arr2) //[2,{a:1}],[1,2,{a:1}]
//记录下上面的打印结果以后修改obj
obj.a = 2;
console.log(arr1,arr2) ////[2,{a:2}],[1,2,{a:2}]
// 说了是浅拷贝,并且原数组也不改变,那咱们就能够用它来实现数组的浅拷贝功能
let num1 = [1,2,3];
//第一种
let num2 = num1.concat();
//第二种
let num2 = [].concat(num1);
num2[0] = 'a';
console.log(num1,num2); // [1, 2, 3] ["a", 2, 3]
复制代码
返回值: 新的 Array 实例
知识点
// concat 和扩展运算符能够快速扁平化数组
const arr = [11, [22, 33], [44, 55], 66];
const flatArr = [].concat(...arr); // [11, 22, 33, 44, 55, 66]
复制代码
obj 须要检测的值。
// 下面的函数调用都返回 true
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
// 这里注意:Array.prototype 也是一个数组,一个属性值不是索引的数组。[constructor: ƒ, concat: ƒ, find: ƒ, findIndex: ƒ, pop: ƒ, …]
Array.isArray(Array.prototype);
// 下面的函数调用都返回 false
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);
Array.isArray({ __proto__: Array.prototype });
复制代码
返回值: 若是对象是 Array,则为true; 不然为false。
知识点
//判断数组的历程
// step one: 使用constructor
var a = [1];
console.log(a.constructor === Array) // true
// 可是原型的contructor属性是能够被改写的,例如在原型继承的时候,咱们都是要把继承过来的prototype的constructor改写成咱们当前的
var a = [1];
a.__proto__.constructor = '1';
console.log(a.constructor === Array) // false
// step two : 使用instanceof
var a = [1];
console.log(a instanceof Array) // true
//可是instanceof不能检测iframes的数组
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]
arr instanceof Array; // false
// step three :万无一失的Object.prototype.toString.call
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
// step four : Array.isArray()
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]
Array.isArray(arr); // true,也能够检测iframes的数组
复制代码
三、数组遍历、映射、过滤、检测、简化等方法
介绍方法以前,先对这些数组方法作一个概述:
首先,大多数方法的第一个参数接收一个函数,而且对数组的每一个元素(或一些元素)调用一次该函数。若是是稀疏数组,对不存在的元素不调用该函数。大多数状况下,调用提供的函数使用三个参数:数组元素、元素的索引和数组自己。一般,只须要第一个参数值,能够忽略后两个参数。
大多数方法,第二个参数是可选的。若是有第二个参数,则调用的第一个函数参数被看作是第二个参数的方法,即当执行第一个函数参数时用做this的值(参考对象)。
方法的返回值很重要,不一样的方法处理返回值的方式也不同。
下面这些方法运行时的规则:
对于空数组是不会执行回调函数的
对于已在迭代过程当中删除的元素,或者空元素会跳过回调函数
遍历次数在第一次循环前就会肯定,再添加到数组中的元素不会被遍历。
若是已经存在的值被改变,则传递给 callback 的值是遍历到他们那一刻的值。
已删除的项不会被遍历到。若是已访问的元素在迭代时被删除了(例如使用 shift()) ,以后的元素将被跳过
callback 为数组中每一个元素执行的函数,该函数接收三个参数:
currentValue(当前值) 数组中正在处理的当前元素。
index(索引) 数组中正在处理的当前元素的索引。
array forEach()方法正在操做的数组。
thisArg (可选) 当执行回调函数时用做this的值(参考对象)。默认值为undefined
注意:
forEach没法中途退出循环,只能用return退出本次回调,进行下一次回调,若是要提早终止,能够把forEach方法放在try块中,并能抛出一个异常,但这种方法是不推荐的。 它与以后会说到的几个方法不一样,老是返回 undefined值,即便你return了一个值。
// 一、 空元素不遍历,undefined和null是会遍历的。
let numberArr = [1,2,,3];
numberArr.forEach(function (value,index,array) {
console.log(value,index,array)
})
//打印信息以下,可见空元素是不会遍历的
//1 0 [1, 2, empty, 3]
//2 1 [1, 2, empty, 3]
//3 3 [1, 2, empty, 3]
let nullArr = [1,2,null,3];
nullArr.forEach(function (value,index,array) {
console.log(value,index,array)
})
//打印信息以下,null是会遍历的
//1 0 (4) [1, 2, null, 3]
//2 1 (4) [1, 2, null, 3]
//null 2 (4) [1, 2, null, 3]
//3 3 (4) [1, 2, null, 3]
//二、已删除的项不会被遍历到。若是已访问的元素在迭代时被删除了,以后的元素将被跳过
let numberArr = [1,2,3];
numberArr.forEach(function (value,index,array) {
if(index === 0) {
delete numberArr[2]; //删除第三项
//或者numberArr.pop()
}
console.log(value,index,array)
})
//打印信息以下:
// 1 0 (3) [1, 2, empty]
// 2 1 (3) [1, 2, empty]
let numberArr1 = [1,2,3,4];
numberArr1.forEach(function (value,index,array) {
if(index === 1) {
numberArr1.shift() //遍历到第二项的时候,删除第一项
}
console.log(value,index,array)
})
// 打印信息以下,遍历到第二项的时候,删除第一项,会跳过第三项
// 1 0 (4) [1, 2, 3, 4]
// 2 1 (3) [2, 3, 4]
// 4 2 (3) [2, 3, 4]
// 三、forEach 遍历的范围在第一次调用 callback 前就会肯定。调用forEach 后添加到数组中的项不会被 callback 访问到。若是已经存在的值被改变,则传递给 callback 的值是 forEach 遍历到他们那一刻的值。
let arr = [1,2,3];
arr.forEach(function (value,index,array) {
if(index === 0) {
arr.push('新增的不会被遍历到')
arr[2] = 4;
}
console.log(value,index,array)
})
// 1 0 (4) [1, 2, 4, "新增的不会被遍历到"]
// 2 1 (4) [1, 2, 4, "新增的不会被遍历到"]
// 4 2 (4) [1, 2, 4, "新增的不会被遍历到"]
// 四、使用thisArg参数 和 箭头函数使用thisArg
let arr = [1,2,3];
let obj = {arr: 'thisArg'}
arr.forEach(function () {
console.log(this.arr)
},obj)
// 打印三次 'thisArg'
let arr = [1,2,3];
let obj = {arr: 'thisArg'}
arr.forEach(() => {
console.log(this.arr)
},obj)
// 打印三次 undefined
// 五、forEach没法中途退出循环,只能用return退出本次回调,进行下一次回调
let arr = [1,2,3];
let result = arr.forEach((value) => {
if(value == 2) {
return value;
}
console.log(value)
})
console.log(result) // undefined ,即便中间return vlaue,也仍是undefined
//打印value的值以下,说明return 并不能终止循环
// 1
// 3
复制代码
返回值: undefined
callback 生成新数组元素的函数,使用三个参 这个函数跟forEach()的函数不一样的是,传递给map()的函数应该有返回值。
currentValue callback 的第一个参数,数组中正在处理的当前元素。 index callback 的第二个参数,数组中正在处理的当前元素的索引。 array callback 的第三个参数,map 方法被调用的数组。 thisArg (可选) 执行 callback 函数时 使用的this 值。
注意: map() 返回的是新数组,它不修改调用的数组。若是是稀疏数组,返回的也是相同方式的稀疏数组:它具备相同的长度,相同索引的缺失元素(由于空值不会调用函数)
let number = [1,2,3];
let doubles = number.map(function (value) {
return value * 2;
})
console.log(number, doubles)
// [1,2,3] [2,4,6]
复制代码
返回值: 一个新数组,每一个元素都是回调函数的结果
知识点 不要用 map 代替 forEach,map 会建立一个新的数组,占用内存。若是你不用 map 的返回值,那你就应当使用 forEach
callback 用来测试数组的每一个元素的函数。调用时使用参数 (element, index, array)。返回true表示保留该元素(经过测试),false则不保留。它接受三个参数:
element 当前在数组中处理的元素 index(可选) 正在处理元素在数组中的索引 array(可选)调用了filter筛选器的数组 thisArg(可选)可选。执行 callback 时的用于 this 的值。
注意:
callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。也就是说filter()会跳过稀疏数组中缺乏的元素,它的返回数组老是稠密的,能够用这个方法压缩稀疏数组的空缺。 filter 不会改变原数组,它返回过滤后的新数组。
let number = [1,2,3,4,5,6];
let small = number.filter((value) => {
return value < 4;
})
console.log(number,small)
// 打印 [1, 2, 3, 4, 5, 6] [1, 2, 3]
//压缩稀疏数组的空缺
let arr = [1,2,3,,5];
let arr1 = arr.filter(() => true);
console.log(arr,arr1)
// 打印 [1, 2, 3, empty, 5] [1, 2, 3, 5]
复制代码
返回值: 一个新的经过测试的元素的集合的数组,若是没有经过测试则返回空数组。
callback 用来测试每一个元素的函数。
thisArg 执行 callback 时使用的 this 值。
注意:
every 方法为数组中的每一个元素执行一次 callback 函数,callback 只会为那些已经被赋值的索引调用。不会为那些被删除或历来没被赋值的索引调用。every 方法在callback第一次返回false后就返回false,而后终止遍历。但若是callback一直返回true,它将会遍历整个数组,最终返回true。
空数组上调用every方法,返回 true,由于空数组没有元素,因此空数组中全部元素都符合给定的条件
every 不会改变原数组
let arr = [12,34,5,23,44];
let num = 0;
let result = arr.every(function (element, index, array) {
num++;
return element > 10;
})
console.log(result,num) // 打印 false 3
// 可见发现5这个小于10的元素后,遍历当即终止,num为3
let arr = [12,34,,23,44];
let num = 0;
let result = arr.every(function (element, index, array) {
num++;
return element > 10;
})
console.log(result,num) // 打印 true 4
// 不会遍历没有赋值的索引位置,因此num为4
let result = [].every(function (element, index, array) {
return element > 10;
})
console.log(result) // 打印 true
复制代码
返回值: 一个布尔值,当全部的元素都符合条件才返回true,不然返回false
callback 用来测试每一个元素的函数
thisArg 可选 执行 callback 时使用的 this 值。
注意:
some 为数组中的每个元素执行一次 callback 函数,直到找到一个使得 callback 返回一个“真值”,这时,some 将会当即返回 true。不然,some 返回 false。callback 只会在那些”有值“的索引上被调用,不会在那些被删除或历来未被赋值的索引上调用。
some 被调用时不会改变数组。
空数组调用some,返回false
// 一个简单的例子说明
function isBiggerThan10(element, index, array) {
return element > 10;
}
[2, 5, 8, 1, 4].some(isBiggerThan10); // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true
// 实现一个跟includes方法相似的功能
let arr = [1,2,3];
function include(value) {
return arr.some((element) => {
return element === value;
})
}
include(2) // true
include(4) // false
let result = [].some(function (element, index, array) {
return element > 10;
})
console.log(result) // 打印 false
复制代码
返回值: 只要数组中的任意一个元素在回调函数中返回的是真值,就返回true,不然为false
callback 执行数组中每一个值的函数,包含四个参数:
accumulator 累加器累加回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(以下所示)。
currentValue 数组中正在处理的元素。
currentIndex (可选) 数组中正在处理的当前元素的索引。 若是提供了initialValue,则索引号为0,不然为索引为1。
array (可选) 调用reduce的数组
initialValue (可选) 用做第一个调用 callback的第一个参数的值。 若是没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。
注意:
reduce为数组中的每个元素依次执行callback函数,不包括数组中被删除或从未被赋值的元素,回调函数第一次执行时,accumulator 和currentValue的取值有两种状况:调用reduce时提供initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;没有提供 initialValue,accumulator取数组中的第一个值,currentValue取数组中的第二个值。即:若是没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。若是提供initialValue,从索引0开始。
若是数组为空且没有提供initialValue,会抛出TypeError 。若是数组仅有一个元素(不管位置如何)而且没有提供initialValue, 或者有提供initialValue可是数组为空,那么此惟一值将被返回而且callback不会被执行。
let arr = [1,2,3,4,5];
let sum = arr.reduce((x,y) => x + y,0);
console.log(sum) // 15
// 看一下initialValue传和不传的区别
let arr = [1,2,3,4,5];
arr.reduce(function (accumulator,currentValue,currentIndex,arr) {
console.log(currentIndex)
return accumulator + currentValue;
})
// 1,2,3,4,5 没传入initialValue,索引是从1开始
arr.reduce(function (accumulator,currentValue,currentIndex,arr) {
console.log(currentIndex)
return accumulator + currentValue;
},10)
// 0,1,2,3,4,5 传入initialValue,索引从0开始
// 应用到二维数组展开
let arr = [[0, 1], [2, 3], [4, 5]].reduce(
(a, b) => a.concat(b)
);
console.log(arr)
// [0, 1, 2, 3, 4, 5]
复制代码
返回值: 函数累计处理的结果
searchElement 要查找的元素
fromIndex (可选)开始查找的位置。 若是该索引值大于或等于数组长度,意味着不会在数组里查找,返回-1。
若是该索引值是负值,表明相对数组末尾的偏移量,即-1表示从最后一个元素开始查找,-2表示从倒数第二个元素开始查找,注意的是,这并不改变其查找顺序,查找顺序仍然是从前向后查询数组。
若是该索引值是负值,其绝对值大于数组长度,则整个数组都将会被查询。其默认值为0。
注意: indexOf 使用严格相等(即 ===)比较 searchElement 和数组中的元素。并且indexOf()不能识别 NaN
let array = [2, 5, 9];
array.indexOf(2) // 0
array.indexOf(7) // -1
array.indexOf(9, 2) // 2
array.indexOf(9, 3) // -1
array.indexOf(2, -1) // -1
array.indexOf(2, -3) // 0
array.indexOf(2, -4) // 0
let array1 = [1,2,NaN];
array1.indexOf(NaN) // -1
复制代码
返回值: 首个被找到的元素在数组中的索引位置; 若没有找到则返回 -1
searchElement 要查找的元素
fromIndex (可选)开始查找的位置。默认为数组的长度减 1,即整个数组都被查找。 若是该值大于或等于数组的长度,则整个数组会被查找。 若是为负值,将其视为从数组末尾向前的偏移。即便该值为负,数组仍然会被从后向前查找。 若是该值为负时,其绝对值大于数组长度,则方法返回 -1,即数组不会被查找。
注意: lastIndexOf 使用严格相等(即 ===)比较 searchElement 和数组中的元素。并且lastIndexOf()不能识别 NaN
let array = [2,5,9,2];
array.lastIndexOf(9) // 2
array.lastIndexOf('9') // -1 严格相等
array.lastIndexOf(7) // -1
array.lastIndexOf(2,4) // 3
array.lastIndexOf(2,3) // 3
array.lastIndexOf(2,2) // 0
array.lastIndexOf(2,-1) // 3
array.lastIndexOf(2,-2) // 0
array.lastIndexOf(2,-4) // 0
array.lastIndexOf(2,-5) // -1
复制代码
返回值: 数组中最后一个符合元素的索引,如未找到返回-1
searchElement 须要查找的元素值。
fromIndex (可选) 从该索引处开始查找 searchElement。默认为 0。若是为负值,则按升序从 array.length + fromIndex 的索引开始搜索。负值绝对值超过长数组度,从0开始搜索。
若是fromIndex 大于等于数组长度 ,则返回 false 。该数组不会被搜索。
注意:
includes解决了两个indexOf的问题:
indexOf方法不能识别NaN indexOf方法检查是否包含某个值不够语义化,须要判断是否不等于-1,表达不够直观
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
[1, 2, 3].includes(3, -4); // true
[1, 2, NaN].includes(NaN); // true
复制代码
返回值: 一个布尔值,根据状况,若是包含则返回 true,不然返回false。
callback 在数组每一项上执行的函数,接收 3 个参数:
element 当前遍历到的元素。 index 当前遍历到的索引。 array 数组自己。 thisArg 可选,指定 callback 的 this 参数。
注意:
这两个方法对数组中的每一项元素执行一次 callback 函数,直至有一个 callback 返回 true。在稀疏数组中,即便对于数组中不存在的条目的索引也会调用回调函数。 这意味着对于稀疏数组来讲,该方法的效率要低于那些只遍历有值的索引的方法。
当找到一个callback判断为true的元素,find方法会当即返回这个元素的值,不然返回 undefined。findIndex会当即返回该元素的索引。若是回调从不返回真值,或者数组的length为0,则findIndex返回-1。
这两个方法都不会修改所调用的数组
// find
let a = [1, 4, -5, 10].find((n) => n < 0); // 返回元素-5
let b = [1, 4, -5, 10,NaN].find((n) => Object.is(NaN, n)); // 返回元素NaN
// findIndex
let a = [1, 4, -5, 10].findIndex((n) => n < 0); // 返回索引2
let b = [1, 4, -5, 10,NaN].findIndex((n) => isNaN(n)); // 返回索引4
// 稀疏数组
let a =[1,,3,4];
let index = 0;
a.find((n) => {
console.log(index++) //0,1,2 第二次是empty也会调用一次,并且返回为true,当即退出
return n === 3;
})
复制代码
返回值:
find 方法,当某个元素经过 callback 的测试时,返回数组中的一个值,不然返回 undefined。 findIndex方法,返回数组中知足提供的测试函数的第一个元素的索引。不然返回-1。
知识点 不要用 find() 代替 some(),一般混用是这种场景,find 返回第一个符合条件的值,直接拿这个值作 if 判断是否存在,可是这个符合条件的值也有可能刚好为 0。 find 是找到数组中的值后对其进一步处理,通常用于对象数组的状况;some 才是检查存在性;二者不可混用。
都是一个新的 Array 迭代器对象
for (let key of ['a', 'b'].keys()) {
console.log(key);
}
// 0
// 1
for (let value of ['a', 'b'].values()) {
console.log(value);
}
// 'a'
// 'b'
for (let value of ['a', 'b'][Symbol.iterator]()) {
console.log(value);
}
// 'a'
// 'b'
for (let [key, value] of ['a', 'b'].entries()) {
console.log(key, value);
}
// 0 "a"
// 1 "b"
复制代码
**扩展几个概念 ** 一、数组的索引和对象key有什么关系? 数组是对象的特殊形式,使用方括号访问数组元素和使用方括号访问对象属性同样。JavaScript将指定的数字索引值转换成字符串——索引1变成"1"——而后将其做为属性名来使用。数组的特别之处在于,当使用小于2^32的非负整数做为属性名时数组会自动维护其length属性。
// 索引到属性名的转化
let arr = [1,2,3];
console.log(arr[1]) // 2
console.log(arr["1"]) // 2
复制代码
全部的数组都是对象,能够为其建立任意名字的属性,不过,只有在小于2^32的非负整数才是索引,数组才会根据须要更新length。事实上数组的索引仅仅是对象属性名的一种特殊类型,这意味着JavaScript数组没有“越界”错误的概念。当查询任何对象中不存在的属性时,不会报错,只会获得undefined
let arr = [];
arr["a"] = 1;
console.log(arr,arr.length) // arr是[a:1] length是0
复制代码
对于使用负数或非整数的状况,数值会转换为字符串,字符串做为属性名来用,当时只能当作常规的对象属性,而非数组的索引。
let arr = [];
arr[-1.23] = 0;
console.log(arr,arr.length) // arr是[-1.23: 0] length是0
复制代码
使用非负整数的字符串或者一个跟整数相等的浮点数时,它就当作数组的索引而非对象属性。
let arr = [];
arr["100"] = 'a';
console.log(arr,arr.length) // arr 是[empty × 100, "a"],length 是101
let arr1 = [];
arr1[1.0000] = 'b';
console.log(arr1,arr1.length) // arr 是[empty, "b"],length 是2
复制代码
2.稀疏数组
稀疏数组就是包含从0开始的不连续索引的数组。一般数组的length属性值表明数组中元素的个数。若是数组是稀疏的,length属性值大于元素的个数
足够稀疏的数组一般在实现上比稠密的数组更慢,更耗内存,在这样的数组中查找元素所用的时间就变得跟常规对象的查找时间同样长了,失去了性能的优点。
let a1 = [,,]; // 数组直接量,该数组是[empty × 2]
0 in a1 // false: a1在索引0处没有元素
let a2 = new Array(3); //[empty × 3],该数组根本没有元素
0 in a2 // false: a2在索引0处没有元素
let a3 = [undefined];
0 in a3 // true: a3在索引0处有一个值为undefined的元素
let a4 = [,undefined];
0 in a4 // fasle: a4在索引0处没有元素
1 in a4 // true: a4在索引1处有一个值为undefined的元素
console.log(a4[0],a4[1]) // undefined undefined,可见数组访问返回undefined,多是稀疏数组,也多是数组元素为undefined
复制代码
三、类数组对象
拥有一个数值length属性和对应非负整数属性的对象看作一种类型的数组
数组跟类数组相比有如下不一样:
当有新元素添加到数组中时,自动更新length属性
设置length为一个较小值将截断数组
从Array.prototype中继承了一些方法
其类属性为'Array'
JavaScript 数组有不少方法特地定义通用,所以他们不只应用在真正的数组并且在类数组对象上都能正确工做,JavaScript权威指南一书说的是:ES5中全部的方法都是通用的,ES3中除了toString()和toLocaleString()意外全部方法也是通用的。
类数组对象显然没有继承自Array.prototype,因此它们不能直接调用数组方法,不过能够间接地使用Function.call方法调用。
// 类数组应用通用方法
let arrayLike = {0: 'name', 1: 'age', 2: 'address', length: 3 }
Array.prototype.join.call(arrayLike,'*') // "name*age*address"
// 还记得当初获取的DOM元素怎么转化成数组么?
functon toArray (DOM) {
return Array.prototype.slice.call(DOM);
}
//对的,这样也能够的
let htmlCollection = document.getElementsByTagName('h2');
let arr1 = Array.prototype.map.call(htmlCollection,function (ele,index){return ele});
console.log(Array.isArray(arr1)) // true
// 还有这样
let arrayLike = {0: 'name', 1: 'age', 2: 'address', length: 3 }
let arr2 = Array.prototype.concat.apply([],arrayLike);
console.log(arr) //["name", "age", "address"]
// ES6如今这样
let arrayLike = {0: 'name', 1: 'age', 2: 'address', length: 3 }
let arr3 = Array.from(arrayLike);
console.log(arr3) // ["name", "age", "address"]
复制代码
四、 JavaScript数组的进化——类型化数组的引入 先说一下广泛意义上的Array,数组是一串 连续 的内存位置,用来保存某些值。JavaScript 中的数组是哈希映射,可使用不一样的数据结构来实现,如链表,上一个元素包含下一个元素的引用。这样其余语言中数组的取值是根据内存位置进行数学计算就能找到,而在JavaScript中就须要遍历链表之类的结构,数组越长,遍历链表跟数据计算相比就越慢。
现代 JavaScript 引擎是会给数组分配连续内存的 —— 若是数组是同质的(全部元素类型相同)。因此在写代码时保证数组同质,以便 JIT(即时编译器)可以使用 c 编译器式的计算方法读取元素是一种优雅的方式。
不过,一旦你想要在某个同质数组中插入一个其余类型的元素,JIT 将解构整个数组,并按照旧有的方式从新建立。
ES6 增长了 ArrayBuffer, 提供一块连续内存供咱们随意操做。然而,直接操做内存仍是太复杂、偏底层。因而便有了处理 ArrayBuffer 的视图(View)。
ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。ArrayBuffer 不能直接操做,而是要经过类型数组对象或 DataView 对象来操做,它们会将缓冲区中的数据表示为特定的格式,并经过这些格式来读写缓冲区的内容。
语法: new ArrayBuffer(length)
参数
length:要建立的 ArrayBuffer 的大小,单位为字节。
返回值:一个指定大小的 ArrayBuffer 对象,其内容被初始化为 0。
异常:若是 length 大于 Number.MAX_SAFE_INTEGER(>= 2 ** 53)或为负数,则抛出一个 RangeError 异常。
复制代码
类型数组对象 一个TypedArray 对象描述一个底层的二进制数据缓存区的一个相似数组(array-like)视图。事实上,没有名为 TypedArray的全局对象,也没有一个名为的 TypedArray构造函数。相反,有许多不一样的全局对象,下面会列出这些针对特定元素类型的类型化数组的构造函数。
new TypedArray(); // ES2017中新增
new TypedArray(length);
new TypedArray(typedArray);
new TypedArray(object);
new TypedArray(buffer [, byteOffset [, length]]);
TypedArray()指的是如下的其中之一:
Int8Array();//8位二进制带符号整数 -2^7~(2^7) - 1,大小1个字节
Uint8Array();//8位无符号整数 0~(2^8) - 1,大小1个字节
Int16Array();//16位二进制带符号整数 -2^15~(2^15)-1,大小2个字节
Uint16Array();//16位无符号整数 0~(2^16) - 1,大小2个字节
Int32Array();// 32位二进制带符号整数 -2^31~(2^31)-1,大小4个字节
Uint32Array();//32位无符号整数 0~(2^32) - 1,大小4个字节
Float32Array();//32位IEEE浮点数,大小4个字节
Float64Array(); //64位IEEE浮点数,大小8个字节
复制代码
应用:
var buffer = new ArrayBuffer(8);
var view = new Int32Array(buffer);
view[0] = 100;
console.log(view)// [100,0],一个八个字节,Int32Array一个元素大小是4个字节,因此只能放下两个元素
复制代码
这里推荐一下个人前端学习交流群:784783012,里面都是学习前端的,若是你想制做酷炫的网页,想学习编程。本身整理了一份2018最全面前端学习资料,从最基础的HTML+CSS+JS【炫酷特效,游戏,插件封装,设计模式】到移动端HTML5的项目实战的学习资料都有整理,送给每一位前端小伙伴,有想学习web前端的,或是转行,或是大学生,还有工做中想提高本身能力的,正在学习的小伙伴欢迎加入学习。