你知道 JS 数组有哪些方法 ?
数组原型方法主要有以下:
join(): 用指定的分隔符将数组每一项拼接为字符串
push(): 向数组的末尾添加新元素
pop(): 删除数组的最后一项
shift(): 删除数组的第一项
unshift(): 向数组首位添加新元素
slice(): 按照条件查找出其中的部分元素
splice(): 对数组进行增删改
fill(): 方法能使用特定值填充数组中的一个或多个元素
filter(): ‘过滤’功能
concat(): 用于连接两个或多个数组
indexOf(): 检测当前值在数组中第一次出现的位置索引
lastIndexOf(): 检测当前值在数组中最后一次出现的位置索引
every(): 判断数组中每一项都是否满足条件
some(): 判断数组中是否存在满足条件的项
includes(): 判断一个数组是否包含一个指定的值
sort(): 对数组的元素进行排序
reverse(): 对数组进行倒序
forEach(): es5及以下循环遍历数组每一项
map(): es6循环遍历数组每一项
copyWithin(): 用于从数组的指定位置拷贝元素到数组的另一个指定位置中
find(): 返回匹配的值
findIndex(): 返回匹配位置的索引
toLocaleString(),toString(): 将数组转换为字符串
flat(),flatMap(): 扁平化数组
entries(),keys(), values(): 遍历数组
数组去重的方式有哪些?时间复杂度分别是多少?
- 双重循环
优点:兼容性好
缺点: 时间复杂度O(n2)
var array = [1,1, ‘1’, ‘2’, ‘1’, 1, 2]
Function unique(arr){
// res 存结果
var res = [];
for(var i = 0, length = arr.length; I< length; I++){
for(var j = 0; length2 = res.length; j < length2; j++){
if(arr[I] === res[j]){
break;
}
}
if(j == length2){
res.push(arr[i])
}
}
return res;
}
unique(array); // [1, ‘1’, ‘2’, 2]
- indexOf方法
优点:时间复杂度降低
缺点:有的浏览器不支持indexOf方法,时间复杂度o(n2)
使用 indexOf 简化内层循环
var array = [1,1,’1’, ‘2’, ‘1’, 1,2]
function unique(arr){
// res 存结果
var res = [];
for(var I = 0, length = arr.length; I < length; I++){
var current = arr[I];
if(res.indexOf(current) === -1){
res.push(current);
}
}
return res;
}
unique(array); // [1, ‘1’, ‘2’, 2]
- 排序后去重
思路:使用快排sort将数组排序,判断当前元素与上一个元素是否相同,相同说明重复,不同添加进res中
优点:已经排好序的数组去重,方法效率高于使用indexOf, 时间复杂度o(n)
缺点: 已经修改数组的顺序,同时存在去重不彻底
var array = [1, 1, ‘1’, ‘2’, ‘1’, 1, 2]
function unique(arr){
// res 存结果
var res = [];
var sortedArray = arr.concat().sort();
console.log(sortedArray, ‘-=-=‘)
var current;
for(var I = 0, length = sortedArray.length; I < length; I++){
// 如果是第一个元素,或者是相邻元素不相同
if(!I || current !== sortedArray[I]){
res.push(sortedArray[I]);
}
current = sortedArray[I]
}
return res;
}
unique(array); // [1, ‘1’, 1, ‘2’, 2]
- 使用es5的filter(Filter + indexOf)
var array = [1,1, ‘1’, ‘2’, ‘1’, 1, 2]
function unique(arr){
// res 存结果
var res = arr.filter(function(item, index, arr){
return arr.indexOf(item) === index;
})
return res;
}
unique(array); // [1, ‘1’, ‘2’, 2]
- 排序去重的方法(filter + sort)
优点:很简洁,思维巧妙,使用filter简化外层循环
缺点:不支持ie9以下的浏览器,时间复杂度o(n * 2)
var array = [1, 1, ‘1’, ‘2’, ‘1’, 1, 2]
Function unique(arr){
// res 存结果
var res = arr.concat().sort().filter(function(item, index, arr){
return !index || item !== arr[index -1]
})
return res;
}
unique(array); // [1, ‘1’, 1, ‘2’, 2]
- Object键值对
var array = [1, 1, ‘1’, ‘2’, ‘1’, 1, 2]
function unique(arr){
// obj 存对象
var obj = {};
var res = arr.filter(function(item, index, arr){
if(obj.hasOwnProperty(item)) return false;
else {
return obj[item] = true;
}
})
return res;
}
unique(array) // [1, ‘2’]
发现1和‘1’是不同的,此方法会判断是同一个值,键值对中只能是字符串,会进行一个隐式转换。和sort排序的转换是一样的,可通过typeof item + item,拼成字符串为key的值避免这个问题
// 优化
function unique(arr){
// obj 存对象
var obj = {};
var res = arr.filter(function(item, index, arr){
if(obj.hasOwnProperty(typeof item + item)) return false;
else {
return obj[typeof item + item] = true;
}
})
return res;
}
unique(array); // [1, ‘1’, ‘2’, 2]
优点: hasOwnProperty 是对象的属性存在性检查方法,对象的属性可以基于hash表实现,对属性的方法时间复杂度达到O(1);
Filter是数组迭代的方法,内部是一个for循环,复杂度O(n),总时间复杂度O(n)
缺点:不兼容ie9以下浏览器
- reduce高阶函数
优点:高阶函数的高级用法
缺点:兼容性问题,对象数组不能使用includes方法来检测,includes区分大小写
includes()方法用来判断一个数组是否包含一个指定的值,根据情况,若包含则返回true,否则返回false
Var array = [1,1,’1’,’2’,’1’,1,2]
function unique(arr){
let newArr = arr.reduce((pre,cur) => {
if(!pre.includes(cur)){
return pre.concat(cur)
}else{
return pre
}
}, []);
return newArr;
}
console.log(unique(array)); // [1, ‘1’, ‘2’, 2]
- es6的Set数据结构
优点:es6语法简单高效
缺点:兼容性问题,加上使用babel编译不是问题
var array = [1,1,’1’,’2’,’1’, 1, 2]
function unique(arr){
return Array.from(new Set(arr));
// 或用扩展运算符
return […new Set(arr)]
}
unique(array); // [1, ‘1’, ‘2’, 2]
- es6的Map数据结构(es6的Map + filter)
var array = [1,1,’1’,’2’,’1’,1,2];
function unique(arr){
var current = new Map();
var res = arr.filter(function(item, index, arr){
if(current.has(item)){
return false;
}else{
return current.set(item, 1);
}
})
return res;
}
unique(array); // [1, ‘1’, ‘2’, 2]
思路:使用map的方法set和has,用has方法来判断是否存在这个key, 若没有值将map中存一个key-value
特殊数据类型比较事例
var str1 = ‘1’;
Var str2 = new String(‘1’);
Console.log(str1 == str2); // true
console.log(str1 === str2); // false
console.log(null == null); // true
console.log(null === null); // true
console.log(undefined == undefined); // true
console.log(undefined === undefined); // true
console.log(NaN == NaN); // false
Console.log(NaN === NaN); // false
console.log(/a/ == /a/); // false
console.log(/a/ === /a/); // false
Console.log({} == {}); // false
Console.log({} === {}); // false
Eg: var arr = [1,2,NaN];
Arr.indexOf(NaN); // -1
//原因: indexOf底层还使用=== 来进行判断,因为NaN === NaN是false, 使用indexOf 还是查不到NaN这个元素
eg: function unique(array){
return Array.from(new Set(array))
}
console.log(unique([NaN, NaN])) // [NaN]
将数组的length设置为 0,取第一个元素会返回什么?
设置length = 0会清空数组,会返回undefined
代码题 :用尽可能多的方法实现数组扁平化
- 使用最基础的递归遍历方式
思路: 使用基础遍历的方式,然后遍历item项是否为数组,若是数组递归执行扁平化函数,并把执行的结果与之前contact,若item项非数组,直接将值push到最初定义的数组中
let array = [1, [2,34,[12,4]],23];
Function flatten(array){
let result = []
for(const item of array){
if(Array.isArray(item)){
result = result.concat(flatten(item))
}else{
result.push(item)
}
}
return result
}
Console.log(flatten(array))
- 使用reduce函数进行递归操作
function flatten(array){
return array.reduce((pre, current, currentIndex, array) => {
if(Array.isArray(current)){
return pre.concat(flatten(current))
}else{
return pre.concat(current)
}
}, [])
}
- while循环结合findIndex与扩展运算符
思路:使用while循环,判断条件,concat以后的数组中是否包含数组类型,如果包含然后使用…扩展运算符进行展开并合并
let array = [1,[2,34,[12,4]],23]
function flatten(array){
while(array.findIndex((item) => Array.isArray(item) > 0)){
array = [].concat(…array)
}
return array
}
console.log(flatten(array))
- 数组强制类型转换
思路:将数组进行强制类型转换,然后使用split分隔为数组,再转换为Number类型
function flatten(array){
return array.toString().split(‘,’).map(item => Number(item)) // ‘array.toString()转换后的结果1,2,34,12,4,23’
}
console.log(flatten(array))
- 使用JSON的函数和正则表达式
思路:先使用JSON.stringify将数组进行转换,然后使用正则匹配去掉[],在最外层增加[],最后使用JSON.parse转换
let array = [1, [2,34, [12,4]],23];
function flatten(array){
let result = JSON.stringify(array); //JSON.stringify 转换后的结果’[1,[2,34,[12,4]],23]’
result = result.replace(/(\[|\])/g, ‘’);
result = ‘[’ + result + ‘]’;
return JSON.parse(result)
}
console.log(flatten(array))
- 使用栈和扩展运算符的方式实现扁平化
思路:创建一个栈的结构,一个空数组,然后遍历栈结构,判断若是数组,使用扩展运算符展开再次扔入栈中,若不是就往新创建的数组头部增加
function flatten(arr){
let res = [];
const stack = [].concat(arr);
console.log(‘hhh’, stack)
while(stack.length > 0) {
console.log(stack.length, stack)
const item = stack.pop();
if(Array.isArray(item){
// 用扩展运算符展开一层
stack.push(…item);
}else {
item !== undefined && res.unshift(item);
}
}
return res;
}
console.log(flatten(array))
- 使用es6中的flatten函数
思路:直接使用es6提供的flatten函数实现扁平化flatten的语法是arr.flatten([depth]) depth可以传递数组的展开深度,(默认不填时,数值是1),即展开一层数组,Infinity代表不论多少层都展开,可设置其他整数,展开固定层数
Let array = [1,[2,34,[12,4]],23]
function flatten(array){
return array.flat(Infinity)
}
console.log(flatten(array))
什么是类数组 ?
类数组对象,指可通过索引属性访问元素并且拥有length属性的对象
常见的类数组:
- arguments对象
- DOM方法的返回结果,比如:document.getElementsByClassName()
- jQuery对象,比如$(‘div’)
类数组和数组的区别和联系
相同点:
- 都可用下标索引访问每个元素
- 都有length属性
不同点: - 数组对象类型:Array, 遍历数组可用for…in.. 和for循环
- 类数组对象类型:Object,遍历数组只能用for循环
类数组怎么转换为数组,说说你知道的所有方法
类数组不具有数组所具有的API
- Array.prototype.slice.call(arguments)该方法是arguments对象转换为数组的写法
function list(){
return Array.prototype.slice.call(arguments);
}
Var li = list(1,2,3,4)
console.log(li). // [1,2,3,4]
- Array.from()
es6新增方法,它可以将类数组对象和可遍历对象转为数组
console.log(Array.from(’star’)); // [’s’, ’t’, ‘a’, ‘r’]
- Array.of()
Es6新增的Array构造函数, 用于将参数中所有值作为元素形成数组
console.log(Array.of(1,2,3,4)); // [1,2,3,4]
arguments 类数组,如何遍历类数组
Arguments是一个对象,属性是从0开始依次递增的数字,还有callee和length属性
遍历类数组,有3个方法:
(1)将数组的方法应用到类数组上,可使用call和apply方法
function foo(){
Array.prototype.forEach.call(arguments, a=> console.log(a))
}
(2) 使用Array.from方法将类数组转化成数组:
function foo(){
const arrArgs = Array.from(arguments)
arrArgs.forEach(a => console.log(a))
}
(3) 使用展开运算符将类数组转化成数组
function foo(){
const arrArgs = […arguments]
arrArgs.forEach(a => console.log(a))
}
判断数组的方式
- 用instanceof判断(object instanceof constructor)
Instanceof运算符可判断某个构造函数的prototype属性所指向的对象是否存在于另外一个要检测对象的原型链上
const a = [];
Const b = {};
console.log(a instanceof Array); // true
console.log(a instanceof Object); // true 在数组的原型链上能找到Object构造函数
- 用constructor判断
缺点:constructor属性可以改写
实例化的数组拥有一个constructor属性,此属性指向生成数组的方法
const a = [];
console.log(a.constructor); // function Array(){ [native code] }
- 用Object的toString方法判断(Object.prototype.toString)
const a = [‘hello’, ‘world’]
Object.prototype.toString.call(a); // ‘[object Array]’
Object.prototype.toString.apply(a); // ‘[object Array]’
- 用Array对象的isArray方法判断(最靠谱的判断数组的方法)
const a = [];
Array.isArray(a); // true
兼容写法:
If (!Array.isArray){
Array.isArray = function(arg){
return Object.prototype.toString.call(arg) === ‘[object Array]’
}
}
新创建一个数组空间
创建数组
1.使用数组字面量表示法
var arr4 = []; // 创建一个空数组
var arr5 = [20]; // 创建一个包含1项数据为20的数组
var arr6 = [‘lily’, ‘lucy’, ’Tom’]; // 创建一个包含3个字符串的数组
2.使用Array构造函数
var arr1 = new Array(); // 创建一个空数组
var arr2 = new Array(20); // 创建一个包含20项的数组
Var arr3 = new Array(‘lily’, ‘Lucy’, ‘Tom’); // 创建一个包含3个字符串的数组
Var array4 = new Array(’23’). // [’23’]
3.Array.of方法创建数组(es6新增)
Array.of()方法总会创建一个包含所有传入参数的数组,而不管参数的数量与类型
let arr = Array.of(1,2);
console.log(arr.length); // 2
Let arr1 = Array.of(3);
console.log(arr1.length); // 1
console.log(arr1[0]); // 3
Let arr2 = Array.of(‘2’);
console.log(arr2.length); // 1
console.log(arr2[0]); // ‘2’
4.Array.from 方法创建数组(es6新增)
在js中将‘非数组对象转换为真正的数组’,在Es6中,将可迭代对象或者类数组对象作为第一个参数传入,Array.from()返回一个数组
function arga(…args){. // …args剩余参数数组,由传递给函数的实际参数提供
let arg = Array.from(args);
console.log(arg);
}
arga(‘arr1’, 26, ‘from’); // [‘arr1’, 26, ‘from’]
用过 ES6 哪些数组的方法,简述他们的特性
- 数组去重
var arr = [1,2,3,4,3,4]
Var arr2 = […new Set(arr)]
- 交换变量的值
let [x,y] = [1,2];
[y,x] = [x,y];
console.log(y)
- 获取字符串中的某个字符
let arr = ‘hellomybo’;
console.log(arr[3]);
- 使用箭头函数代替回调函数
let a2 = [1, 2, 3].map(x => x * x);
console.log(a1, a2);
- 合并数组
var arr1 = [‘a’, ‘b’];
Var arr2 = [‘c’];
Var arr3 = [‘d’, ‘e’];
[…arr1, …arr2, …arr3] // [‘a’, ‘b’, ‘c’, ‘d’, ‘e’]
- 字符串反转
let str = ‘12345678900987654321’
[…str].reverse().join(‘’)
- 过滤需要的数值 和获得计算后的数值
过滤:
[‘a’, , ‘b’].filter(x => true). // [‘a’, ‘b’]
计算:
let arr = [1,2,3,4].map(x => x+1);
console.log(arr)
- 数组降维 使用generator迭代器
var arr = [1, [[2,3],4], [5,6]];
var flat = function*(a) {
var length = a.length;
for(var I = 0; I < length; I++){
var item = a[I];
if(typeof item !== ’number’){
yield* flat(item);
} else {
yield item;
}
}
}
for(var f of flat(arr)){
console.log(f)
}
- splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目
var arr = new Array(6)
arr[0] = ‘George’
arr[1] = ‘John’
arr[2] = ’Thomas’
arr[3] = ‘James’
arr[4] = ‘Adress’
arr[5] = ‘Martin’
document.write(arr + ‘<br/>’)
arr.splice(2,1, ‘William’)
document.write(arr)
// George, John, Thomas, James, Adress, Martin
// George, John, William, James, Adress, Martin
- 置空数组
var arr = [1,2,3,4,5,6,7,8]
arr.length = 0;
console.log(arr) // []
- 将数组转换为对象
使用展开运算符…
var obj = {…arr}
console.log(obj). // {0: 1, 1:2, 2:3, 3:4, 4: 5, 5:6, 6:7, 7:8}
- 用数据填充数组
var yc = new Array(3).fill(‘acini’)
console.log(yc)
// [‘acini’, ‘acini’, ‘acini’]
- 从数组中删除虚值
在js中,虚值有 false, 0, ‘’, null, NaN, undefined 可用.filter()方法来过滤这些虚值
var mix = [0, ‘blue’, ‘’, NaN, 90, true, undefined, false]
Var mixture = mix.filter(Boolean)
console.log(mixture) // [‘blue’, 90, true]
- 从数组中获取随机值
从数组中随机选择一个值,可根据数组长度获得一个随机索引
var arr = [’太阳光大’, ‘成功是优点的发挥’, ‘不要小看自己’,‘口说好话’,‘手心向下是助人’]
alert(arr[Math.floor(Math.random()*arr.length)]);
- 对数组中的所有值求和
var you = [1,2,3,34,456,6]
Var sum = you.reduce((x,y)=> x+y)
数组中的方法如何实现 break
- 在for循环中想调出整个循环是break;
let func = () => {
for(let I = 1; I <= 5; I++){
console.log(I);
if(I == 3){
break
}
}
}
func();
// 1
// 2
// 3
2.使用try…catch来调出循环
try{
let list = [1,2,3,4,5];
list.forEach(el =>{
console.log(el);
if(el == 3){
throw new Error(‘finish’)
}
})
}catch(e){
if(e.message == ‘finish’){
console.log(‘All finish!’)
}else{
console.log(e.message)
}
}
3.every()使用return false 跳出循环(需要配合return true)
every()返回一个boolean,判断每个元素是否符合func条件,数组里面所有的元素都符合才返回true
let func = () => {
let list = [1,2,3,4,5];
list.every(el => {
if(el == 3){
console.log(el);
return false;
}else {
console.log(el);
return true;
}
})
}
func()
4.some()使用return true 跳出循环
some()返回一个boolean,判断是否有元素是否符合func条件,数组里面所有元素有一个符合条件就返回true
let func = () => {
let list = [1, 2, 3, 4, 5];
list.some(el => {
console.log(el);
if(el == 3){
return true;
}
})
}
func()
5.map()不会跳出循环
语法糖:map()返回一个新的Array, 每个元素为调用func结果,新数组长度和原来一样,逐一对原来数据每个元素进行操作
不能终止循环,使用break会报错,用return false ,输出结果会有false, 循环不会终止
使用return true:
let func = () => {
let list = [1,2,3,4,5];
return list.map(el => {
if(el == 3){
return true
}
return el;
})
}
func()
// [1,2,true,4,5]
比较常用的数组方法 map() reduce() find() findIndex() push() .... 哪些可以改变原数组,哪些不可以改变
-
改变原数组
Es5:
splice()可删除从index处开始的零个或多个元素
sort()
pop()删除尾部元素,返回删除的值
push()数组尾部添加,返回新数组长度
shift()数组头部元素删除,返回删除元素
unshift()数组头部增加,返回新数组长度
reverse()Es6:
copyWithin()
Fill -
不改变原数组方法
es5:
Slice, join, toLocateString, toStringin, cancat, indexOf, lastIndexOf,
Es7:
Includes
Js中遍历数组并不改变原数组的方法有:
es5:
forEach, every, some, filter, map, reduce, reduceRight,
Es6:
Find, findIndex, keys, values, entries
JS 中 filter 方法如何使用
filter()方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素
filter()不会对空数组进行检测,不会改变原始数组
var ages = [32, 33, 16, 40];
function checkAdult(age){
return age >= 18;
}
function myFunction(){
document.getElementById(‘demo’).innerHTML = ages.filter(checkAdult);
}
32, 33, 40
网友评论