批量制造数据
fill + map
function createData(){
return new Array(1000).fill(null)
.map((v,i) => ({name: `name ${i + 1}`}))
}
const data = createData();
Array.from
function createData() {
return Array.from({length: 1000}, (v,i) =>
{ name: `name${i + 1}`}
)
}
const data = createData()
数组去重
set
- 对象不能去重
const arr1 = [1, 2, 3];
const arr2 = [3, 4, 5];
console.log(new Set([...arr1, ...arr2]));
非set
- 不能对NaN去重
function mergeArray(arr1, arr2){
// 克隆
var arr = arr1.slice(0);
var v;
for(let i = 0; i < arr2.length; i++){
v = arr2[i];
if(~arr.indexOf(v)){
continue;
}
arr.push(v);
}
return arr;
}
类数组
- 数组对象字面量
- new Array
- Array.from(ES6)
- Array.of(ES6)
- Array.prototype.slice
- Array.prototype.concat
类数组:是有一个length属性和从零开始索引的属性,但是没有Array的内置方法,比如forEach()和map()等一种特殊对象
- 普通对象
- 必须有length属性,可以有非负整数索引
- 本身不具备数组所具备的方法
常见的类数组 - arguments
常见的类数组 - DOM相关:NodeList, HTMLCollection,DOMTokenList
字符串:具备类数组的所有特性,但是类数组一般是指对象
数组 | 类数组 | |
---|---|---|
自带方法 | 多个方法 | 无 |
length | 有 | 有 |
instanceof | Array | Object |
constructor | [Function: Array] | [Function: Object] |
Array.isArray | true | false |
// 严格判断类数组
function isArrayLikeObject(arr){
if(arr == null || typeof arr !== 'object')
return false;
const lengthMaxValue = Math.pow(2, 53) -1;
if(!Object.prototype.hasOwnProperty.call(arr, 'length'))
return false;
if(typeof arr.length != 'number') return false;
if(!isFinite(arr.length)) return false;
if(Array === arr.constructor) return false;
if(arr.length >= 0 && arr.length < lengthMaxValue){
return true
}else{
return false
}
}
类数组如何转化为数组
- slice,concat等
- Array.from
- Array.apply
- 复制遍历
数组注意事项
数据长度与空元素
// 末尾的逗号表示可添加
const arr1 = [1,];
const arr2 = [1, ,]
const arr3 = new Array('10')
const arr4 = new Array(10)
console.log(arr1.length) // 1
console.log(arr2.length) // 2
console.log(arr3.length) // 1
console.log(arr4.length) // 10
数组空元素:empty 数组的空位,指数组的某一个位置上没有任何值。简单来说,就是数组上没有对应的属性
一般的遍历,自动跳过空位,forEach,reduce等
- Join和toString 空位 视为空字符串
稀疏数组: 有空元素的数组,就是稀疏数组
如何避免创建稀疏数组
- Array.apply(null, Array(3))
- […new Array(3)]
- Array.from(Array(3))
数组不会自动添加分号
( [ + - / 作为一行代码的开头,很可能产生意外的情况,所以没事代码最后写个分号,准保没错
indexOf 与 includes
方法 | 返回值 | 能否查找NaN | [ , , ] | undefined |
---|---|---|---|---|
indexOf | number | ❌ | ❌ | ✅ |
includes | boolean | ✅ | ✅ | ✅ |
数组可变长度问题
- length 代表数组中元素个数,数组额外附加属性不计算在内
- length 可写,可以通过修改length改变数组的长度
- 数组操作不存在越界,找不到下标,返回undefined
数组查找或者过滤
方法 | 返回结果类型 | 返回短路操作 | 是否全部满足 | 遍历空元素 |
---|---|---|---|---|
some | boolean | ✅ | ❌ | ❌ |
find | undefined | ✅ | ❌ | ✅ |
findIndex | number | ✅ | ❌ | ✅ |
every | boolean | ✅ | ✅ | ❌ |
filter | array | ❌ | ❌ | ❌ |
数组操作非线形存储问题
- 数组默认存储为线形存储
- 存储结构改变必然产生不必要代价,我们尽量线性递增
数组高级用法
万能数据生成器
const createValues = (creator, length = 10) => Array.from({length}, creator)
随机数生成器
const createRandomValues = (len) => createValues(Math.random, len);
序列生成器
const createRange = (start. stop, step) =>
createValues((_, i) => start + (i * step), (stop - start)/ step + 1)
数据生成器
function createUser(v, index){
return {
name: `user-${index}`,
age: Math.random() * 100 >> 0
}
}
清空数组
- Array.prototype.slice(0)
- Array.prototype.length = 0
数组去重
- Array.from(new Set(arr)) 问题:对于属性键和属性值都相同的对象没有作用
- Array.prototype.filter + key 唯一 问题:如何确保key唯一
求交集
- Array.prototype.filter + includes 判断 问题:1.引用类型相同的判断 2.性能问题
function intersectSet(arr1, arr2){
return [..new Set(arr1)].filter(item => arr2.includes(item))
}
- 引用数据:Array.prototype,forEach + Map + key 唯一
- 基础数据:Array.prototype.forEach + Map + filter
// 引用类型
function intersect(arr1, arr2, key){
const map = new Map();
arr1.forEach(val => map.set(val[key]))
return arr2.filter(val =>{
return map.has(val[key]);
})
}
// 原始类型
function intersectBase()(arr1, arr2){
const map = new Map();
arr1.forEach(val => map.set(val))
return arr2.filter(val =>{
return map.has(val);
})
}
从数组中删除虚值
- Array.prototype.filter(Boolean)
获取数组中最大值和最小值
- Math.max.apply(Math, numArray)
- Math.min.apply(Math, numArray)
queryString
- 作用:页面传递参数
- 规律:地址url问号拼接的键值对
现代Web API查询queryString: URLSearchParams、URL
const urlSP = new URLSearchParams(location.search);
function getQueryString(key){
return urlSP.get(key)
}
const urlObj = location.search.slice(1)
.split("&")
.filter(Boolean)
.reduce(function(obj, cur){
var arr = cur.split("=");
if(arr.length != 2){
return obj;
}
obj[decodeURLComponent(arr[0])] = decodeURLComponent(arr[1]);
return obj;
},{})
compose封装
function compose(...funcs){
if(funcs.length === 0){
return arg => arg
}
return funcs.reduce((a,b) => (...args) => a(b(...args)))
}
runPromises封装
function runPromises(promiseCreators, initData){
return promiseCreators
.reduce(function(promise,next){
return promise.then((data) => next(data))
}, Promise.resolve(initData))
}
手写数组方法
Array.isArray
Array.isArray = function(obj){
return Object.prototype.toString.call(obj) === '[object Array]';
}
Array.prototype.entries
- 作用:返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对, 可以用next 和 let of 遍历
Array.prototype.entries = function() {
const O = Object(this);
let index = 0;
const length = O.length;
function next(){
if(index < length){
return { value: [index, O[index++], done: false]}
}
return { value: undefined, done: true }
}
return {
next,
[Symbol.iterator](){
return{
next
}
}
}
}