【干货建议收藏】JavaScript 详细数组相关方法及示例(实例、静态方法,如何判断,生成数组,数组的解构赋值)

33 阅读9分钟

数组实例方法

push

//向数组末尾添加元素,会改变原数组,返回值是新数组的长度
const arr = ['苹果','华为','三星']
const pushArr = arr.push('小米')
console.log(pushArr) //4
console.log(arr) //['苹果','华为','三星','小米']

pop

//向数组末尾删除元素,会改变原数组,返回被删除的元素
const arr = ['苹果','华为','三星']
const popArr = arr.pop();
console.log(arr); //['苹果','华为']
console.log(popArr); // 2

unshift

//向数组头部添加元素,会改变原数组,返回值是新数组的长度
const arr = ['苹果','华为','三星']
const unshiftArr = arr.unshilt('小米')
console.log(arr) //['小米','苹果','华为','三星']
console.log(unshiltArr) //4

shift

//向数组头部删除元素,会改变原数组,返回被删除的元素
const arr = ['苹果','华为','三星']
const shiftArr = arr.shift()
console.log(arr) //['苹果','华为']
console.log(shiftArr) //['三星']

slice

//截取数组部分元素,不会改变原数组,返回值是被截取的元素
const arr = ['苹果','华为','三星','小米']
const spliceArr = arr.slice() // 截取所有元素
console.log(arr) //['苹果','华为','三星','小米']
console.log(spliceArr) // ['苹果','华为','三星','小米']

const arr1 = ['苹果','华为','三星','小米']
const sliceArr1 = arr1.slice(1); //截取数组下标为1及剩下的元素
console.log(arr1) // ['苹果','华为','三星','小米']
console.log(sliceArr1) // ['华为','三星','小米']

const arr2 = ['苹果','华为','三星','小米']
const sliceArr2 = arr2.slice(1,3); //截取数组下标为1到2的元素
console.log(arr2) // ['苹果','华为','三星','小米']
console.log(sliceArr2) // ['华为','三星']

splice

//向数组进行删除、替换、插入元素,会改变原数组,返回值是被删除的元素
const arr1 = ['苹果','华为','三星','联想']
const spliceArr1 = arr1.splice(1,2) // 从数组下标为1开始,删除2个元素
console.log(arr1) //['苹果','联想']
console.log(spliceArr1) // ['华为','三星']

const arr2 = ['苹果','华为','三星','联想']
const spliceArr2 = arr2.splice(1,1,'小米') //从数组下标为1开始,删除1个元素,插入元素'小米'
console.log(arr2) //['苹果','小米','三星','联想']
console.log(spliceArr2) // ['华为']

const arr3 = ['苹果','华为','三星','联想']
const spliceArr3 = arr3.splice(1,0,'小米') //从数组下标为1开始,删除0个元素,插入元素'小米'
console.log(arr3) //['苹果','小米','华为','三星','联想']
console.log(spliceArr3) // []

concat

//合并两个或多个数组,不会改变原数组,返回值是合并后的数组
const arr1 = ['苹果','华为']
const arr2 = ['三星','联想']
const concatArr1 = arr1.concat() //复制数组
console.log(concatArr1) //['苹果','华为']

const concatArr2 = arr1.concat(arr2,concatArr1) //合并两个数组
console.log(concatArr2) //['苹果','华为','三星','联想','苹果','华为']

const concatArr3 = arr1.concat(concatArr1,arr2,'小米') //合并数组并添加其他值
console.log(concatArr3) // ['苹果','华为','苹果','华为','三星','联想','小米']

join

//将数组中的所有元素转换为字符串,不会改变原数组,返回值是转换后的字符串
const arr = ['苹果','华为','小米']
const joinArr1 = arr.join() //默认以逗号,为分割符连接字符串
console.log(joinArr1) //苹果,华为,小米

const joinArr2 = arr.join('-')  //以-为分隔符连接字符串
console.log(joinArr2) //苹果-华为-小米

const joinArr3 = arr.join(`${' | '}`);  //使用模板字符串,以 | 为分隔符连接字符串
console.log(joinArr3) //苹果 | 华为 | 小米

reverse

//翻转数组,会影响原数组,返回值是翻转后的数组
const arr = ['苹果','华为','小米']
const reverseArr = arr.reverse()
console.log(arr) // ['小米','华为','苹果']
console.log(reverseArr) // ['小米','华为','苹果']

sort

//对数组元素进行排序,会影响原数组,返回值是排序后的新数组
const arr = ['苹果','华为','小米']
const sortArr = arr.sort()// 默认排序,将数组元素转换为字符串,并按照字典顺序(即字符串的 Unicode 编码顺序)进行排序
console.log(arr) // ['华为','小米','苹果']
console.log(sortArr) // ['华为','小米','苹果']

const arr1 = ['20','12','21','4','3']
const sortArr1 = arr1.sort(( a , b ) => a - b ) //升序
console.log(arr1) // ['3', '4', '12', '20', '21']
console.log(sortArr1) // ['3', '4', '12', '20', '21']

const arr2 = ['20','12','21','4','3']
const sortArr2 = arr2.sort(( a , b ) => b - a ) //降序
console.log(arr2) // ['21', '20', '12', '4', '3']
console.log(sortArr2) // ['21', '20', '12', '4', '3']

const people = [
  { name: 'John', age: 25 },
  { name: 'Jane', age: 22 },
  { name: 'Doe', age: 30 }
]
people.sort((a, b) => a.age - b.age) //根据年龄升序排列
console.log(people) // [{name: 'Jane', age: 22}, {name: 'John', age: 25}, {name: 'Doe', age: 30}]

map

//遍历数组元素进行处理,不会影响原数组,返回值是处理后的新数组
//map(callback,?thisArg),callback(必选):element,index,array,thisArg:(可选)指定在调用回调函数时使用的this值。
const people = [
  { name: 'John', age: 25 },
  { name: 'Jane', age: 22 },
  { name: 'Doe', age: 30 }
]
const mapArr = people.map((item,index,array) => item.name) //item:当前元素,index:当前元素下标,array:原数组
console.log(mapArr) // ['John','Jane','Doe']

const person = {
  name: 'Alice',
  sayHello: function() {
    return this.name + ', says hello!'
  }
}
const greetings = ['Good morning', 'Good afternoon', 'Good night']
const personGreetings = greetings.map(person.sayHello, person)
console.log(personGreetings) // ['Alice, says hello!', 'Alice, says hello!', 'Alice, says hello!']

forEach

//遍历数组元素进行处理,可能会影响原数组,没有返回值
//forEach(callback,?thisArg),callback(必选):element,index,array,thisArg:(可选)指定在调用回调函数时使用的this值。
const people = [
  { name: 'John', age: 25 },
  { name: 'Jane', age: 22 },
  { name: 'Doe', age: 30 }
]
const arr = []
people.forEach((item,index,array) => arr.push(item.name)) //item:当前元素,index:当前元素下标,array:原数组
console.log(arr) //['John','Jane','Doe']

const numArr = [1,22,3,4,5]
numArr.forEach((item,index)=>numArr[index] = item * 2) //会影响原数组
console.log(numArr) // [2, 44, 6, 8, 10]

const person = {
  name: 'Alice',
  sayHello: function() {
    console.log(this.name + ', says hello!');
  }
}
const greetings = ['Good morning', 'Good afternoon', 'Good night']
greetings.forEach(person.sayHello, person)
// Alice, says hello!
// Alice, says hello!
// Alice, says hello!

includes

//遍历数组,测试判断是否存在指定的元素,如果至少有一个元素通过测试,则返回true,否则返回false。不会改变原数组,返回值是测试结果。
//如果数组为空,立即返回 false
const numbers = [1, 2, 3, 4, 5];
const res = numbers.includes(3)
console.log(numbers) // [ 1, 2, 3, 4, 5 ]
console.log(res) // true

const objArr = [{ id: 1, name: '张三' }, { id: 2, name: '李四' }]
const res2 = objArr.includes({ id: 1, name: '张三' })
console.log(objArr) // [ { id: 1, name: '张三' }, { id: 2, name: '李四' } ]
console.log(res2) //false 原因:includes() 方法使用的是严格的相等性比较(===),意味着两个对象必须是同一个对象实例,才能被认为是相等的
const objArr1 = [{ id: 1, name: '张三' }, { id: 2, name: '李四' }]
const res3 = objArr1.some(item => item.id === 1 && item.name === '张三'); //可以换成用some()方法
console.log(res3) // true

some

//遍历数组,对每个元素进行测试,如果至少有一个元素通过测试,则返回true,否则返回false。不会改变原数组,返回值是测试结果。
//如果数组为空,立即返回 false;some() 方法会跳过数组中的空位( undefined 、 null ),但会处理显式设置为 `undefined` 或 `null` 的元素。
const arr = [1, 2, 3, 4, 5]
const res = arr.some(item => item > 3)
console.log(arr) // [ 1, 2, 3, 4, 5 ]
console.log(res) // true

const objArr = [
    { name: '张三', age: 18 },
    { name: '李四', age: 20 },
    { name: '王五', age: 22 }
]
const res2 = objArr.some(item => item.age > 20)
console.log(objArr) // [ { name: '张三', age: 18 }, { name: '李四', age: 20 }, { name: '王五', age: 22 } ]
console.log(res2) // true

const hasArr = ['a', 'b', 'c']
const res3 = hasArr.some(item => item === 'd')
console.log(hasArr) // [ 'a', 'b', 'c' ]
console.log(res3) // false

const mapSomeArr = [1, 2, 3, 4, 5]
const res4 = mapSomeArr.map(m => m * 2).some(item => item === 8)
console.log(mapSomeArr) // [ 1, 2, 3, 4, 5 ]
console.log(res4) // true

every

//遍历数组,对每个元素进行测试,每个元素都通过测试,则返回true,否则返回false。不会改变原数组,返回值是测试结果。
//如果数组为空,不管测试函数是什么都立即返回 true;every() 方法会跳过数组中的空位( undefined 、 null ),但会处理显式设置为 `undefined` 或 `null` 的元素。
const arr = []
const res0 = arr.every(()=>false)
const res01 = arr.every(()=>true)
const res03 = arr.every(item => item > 0)
console.log(res0) // true
console.log(res01) // true
console.log(res03) // true

const numbers = [2, 4, 6, 8]
const res = numbers.every(num => num > 0)
console.log(numbers) // [ 2, 4, 6, 8 ]
console.log(res) // true 

const people = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 },
    { name: 'Charlie', age: 35 }
];
const res1 = people.every(person => person.age >= 18)
console.log(res1) // true

const uniqueIds = [1, 2, 3, 4]
const allUnique = uniqueIds.every((value, index, self) => self.indexOf(value) === index) //验证数组中所有元素的唯一性:
console.log(allUnique) // true

const mainArray = [1, 2, 3, 4, 5]
const subArray = [1, 3, 5]
const allInMainArray = subArray.every(element => mainArray.includes(element)) //确认所有元素都在另一个数组中:
console.log(allInMainArray) // true

filter

//遍历数组,对每个元素进行测试筛选,不会改变原数组,返回值是筛选后的数组。
// filter方法会跳过数组中的空位( undefined 、 null ),但会处理显式设置为 undefined 或 null 的元素。
const arr = [1, undefined, 2, null, 3]
const filtered = arr.filter(item => item === null || item === undefined)
console.log(filtered) // [undefined, null]

const numbers = [1, 2, 3,null, 4, 5, 6]
const evenNumbers = numbers.filter(num => num % 2 === 0)
console.log(evenNumbers) // [2, 4, 6]

const people = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 },
    { name: 'Charlie', age: 35 }
]
const adults = people.filter(person => person.age >= 28)
console.log(adults) // [{ name: 'Bob', age: 30 }, { name: 'Charlie', age: 35 }]

const items = [1, 2, 2, 3, 4, 4, 5]
const uniqueItems = items.filter((item, index, self) => self.indexOf(item) === index) //筛选出数组中唯一的元素:
console.log(uniqueItems) // [1, 2, 3, 4, 5]

find

//遍历数组,对每个元素进行条件查询,不会改变原数组,返回值是满足条件的第一个元素,如果不存在满足条件的元素,则返回 undefined。
// find方法会跳过数组中的空位( undefined 、 null ),但会处理显式设置为 undefined 或 null 的元素。
const arr = [1, 2, 3, null, 9, 10]
const res = arr.find(item => item > 5)
console.log(res) // 9

const people = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 },
    { name: 'Charlie', age: 35 }
  ]
 const alice = people.find(person => person.name === 'Alice')
 console.log(alice) // { name: 'Alice', age: 25 }

findIndex

//遍历数组,对每个元素进行条件查询,不会改变原数组,返回值是满足条件的第一个元素的索引,如果不存在满足条件的元素,则返回 -1。
// findIndex方法会跳过数组中的空位( undefined 、 null ),但会处理显式设置为 undefined 或 null 的元素。
const numbers = [1, 3, 5, 8, 10]
const indexFirstEven = numbers.findIndex(num => num % 2 === 0)
console.log(indexFirstEven) // 3

const people = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 },
    { name: 'Charlie', age: 35 }
  ]
 const indexAlice = people.findIndex(person => person.name === 'Alice')
 console.log(indexAlice) // 0

findLast

//遍历数组,从数组的末尾开始条件查找,不会改变原数组,返回值是满足条件的第一个元素,如果不存在满足条件的元素,则返回 undefined。
// findLast方法会跳过数组中的空位( undefined 、 null ),但会处理显式设置为 undefined 或 null 的元素。
const arr = [1, 2, 3, null, 9, 10]
const res = arr.findLast(item => item > 5)
console.log(res) // 10

const people = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 },
    { name: 'Charlie', age: 35 },
    { name: 'Alice', age: 35 }
  ]
const alice = people.findLast(person => person.name === 'Alice')
console.log(alice) // { name: 'Alice', age: 35 }

findLastIndex

//遍历数组,从数组的末尾开始条件查找,不会改变原数组,返回值是满足条件的第一个元素的索引,如果不存在满足条件的元素,则返回 -1。
// findLastIndex方法会跳过数组中的空位( undefined 、 null ),但会处理显式设置为 undefined 或 null 的元素。
const numbers = [1, 3, 5, 8, 10]
const indexFirstEven = numbers.findLastIndex(num => num % 2 === 0)
console.log(indexFirstEven) // 4

const people = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 },
    { name: 'Charlie', age: 35 },
     { name: 'Alice', age: 35 }
  ]
const indexAlice = people.findLastIndex(person => person.name === 'Alice')
console.log(indexAlice) //3

reduce

//用于对数组中的每个元素执行一个提供的函数(reducer),从而将所有元素缩减为单个值,可以用来执行求和、拼接字符串、查找最大最小值等操作。
//接受一个初始值作为第二个参数,并且可以通过累积器(accumulator)来跟踪中间结果。
//reduce方法会跳过数组中的空位( , ),但会处理显式设置为 undefined 或 null 的元素。
const arr = [1, 2, , 3, undefined, null, 4, 5]
const sum = arr.reduce((accumulator, currentValue) => {
    console.log(currentValue)
    return accumulator + currentValue
}, 0) //数组元素求和
console.log(sum) //NaN
//输出:
//1
//2
//3
//undefined
//null
//4
//5

const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'banana']
const count = fruits.reduce((acc, fruit) => {
    acc[fruit] = (acc[fruit] || 0) + 1 //统计每个元素的出现次数
    return acc
}, {})
console.log(count) //{ apple: 2, banana: 3, orange: 1 }

const numbers = [10, 20, 30, 40, 50]
const max = numbers.reduce((maxValue, current) => Math.max(maxValue, current), numbers[0]) //查找数组中的最大值
console.log(max) // 50

const nestedNumbers = [1, [2, 3], [4, [5, 6]]]
const flatArray = nestedNumbers.reduce((acc, val) =>
    acc.concat(Array.isArray(val) ? val.flat() : val), []) //数组扁平化
console.log(flatArray) //  [1, 2, 3, 4, 5, 6]

const keyValuePairs = [['a', 1], ['b', 2], ['c', 3]]
const object = keyValuePairs.reduce((obj, [key, value]) => {
    obj[key] = value //将数组转换为对象
    return obj
}, {})
console.log(object) // 输出: { a: 1, b: 2, c: 3 }

reduceRight

//与 reduce() 类似,但它从数组的末尾开始向前处理。用于对数组中的每个元素执行一个提供的函数(reducer),从而将所有元素缩减为单个值,可以用来执行求和、拼接字符串、查找最大最小值等操作。
//接受一个初始值作为第二个参数,并且可以通过累积器(accumulator)来跟踪中间结果。
//reduceRight方法会跳过数组中的空位( , ),但会处理显式设置为 undefined 或 null 的元素。
const arr = [1, 2, , 3, undefined, null, 4, 5]
const sum = arr.reduceRight((accumulator, currentValue) => {
    console.log(currentValue)
    return accumulator + currentValue
}, 0) //数组元素求和
console.log(sum) //NaN
//输出:
//1
//2
//3
//undefined
//null
//4
//5

const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'banana']
const count = fruits.reduceRight((acc, fruit) => {
    acc[fruit] = (acc[fruit] || 0) + 1 //统计每个元素的出现次数
    return acc
}, {})
console.log(count) //{ apple: 2, banana: 3, orange: 1 }

const numbers = [10, 20, 30, 40, 50]
const max = numbers.reduceRight((maxValue, current) => Math.max(maxValue, current), numbers[0]) //查找数组中的最大值
console.log(max) // 50

const nestedNumbers = [1, [2, 3], [4, [5, 6]]]
const flatArray = nestedNumbers.reduceRight((acc, val) =>
    acc.concat(Array.isArray(val) ? val.flat() : val), []) //数组扁平化
console.log(flatArray) //  [1, 2, 3, 4, 5, 6]

const keyValuePairs = [['a', 1], ['b', 2], ['c', 3]]
const object = keyValuePairs.reduceRight((obj, [key, value]) => {
    obj[key] = value //将数组转换为对象
    return obj
}, {})
console.log(object) // 输出: { a: 1, b: 2, c: 3 }

indexOf

//遍历数组,从数组的开始位置向后查找,对每个元素进行条件查询,不会改变原数组,返回值是满足条件的第一个元素的索引,如果不存在满足条件的元素,则返回 -1。
// indexOf方法会跳过数组中的空位( undefined 、 null ),但会处理显式设置为 undefined 或 null 的元素。
const numbers = [1, 2, 3, 4, 5]
const index = numbers.indexOf(3)
console.log(index) //2

const arr = [1, 2, 3, 4, 5,3]
const res = arr.indexOf(3 ,4) //第一个参数是查找元素,第二个参数是查找位置,即从下标4开始查找(包括4)
console.log(res) //5

const people = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 },
    { name: 'Charlie', age: 35 }
  ];
  const objIndex = people.indexOf(person => person.name === 'Bob') //indexOf() 使用的是严格的相等性比较(===),意味着两个对象必须是同一个对象实例,才能被认为是相等的
  console.log(objIndex) //-1
  
/*
*补充 findIndex 与 indexOf 的区别
1.参数不同:
findIndex接受一个参数(一个回调函数:用于定义查找的条件。回调函数接收三个参数:当前元素的值、当前元素的索引、数组本身),
而indexOf接受两个参数,第一个参数是查找的元素,第二个参数是开始查找的位置。

2.比较方式不同:
findIndex使用回调函数判断,而indexOf使用===比较。
意味着findIndex可以找到数组中元素值与回调函数返回值相同的元素,而indexOf只能找到数组中元素值与查找元素相同的元素。
findIndex可以在对象数组中查找满足条件的值,而indexOf则不行,indexOf适合查找基本类型的元素(数字、字符串、布尔值)

3.返回值不同:
findIndex与indexOf返回找到的元素的索引,如果找不到元素都返回-1。但是findIndex接受一个回调函数,所以它可以返回数组中满足条件的任何元素的索引,而不仅仅是与特定值相等的元素。
*/

lastIndexOf

//遍历数组,从数组的末尾位置向前查找,对每个元素进行条件查询,不会改变原数组,返回值是满足条件的最后一个元素的索引,如果不存在满足条件的元素,则返回 -1。
// lastIndexOf方法会跳过数组中的空位( undefined 、 null ),但会处理显式设置为 undefined 或 null 的元素。
const numbers = [1, 2, 3, 4, 2, 5]
const index = numbers.lastIndexOf(3)
console.log(index) //2

const arr = [1, 2, 3, 4, 2, 5, 3]
const res = arr.lastIndexOf(3, 4) //第一个参数是查找元素,第二个参数是查找位置,即从下标4开始查找(包括4)
console.log(res) //2

const people = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 },
    { name: 'Charlie', age: 35 }
];
const objIndex = people.lastIndexOf(person => person.name === 'Bob') //lastIndexOf() 使用的是严格的相等性比较(===),意味着两个对象必须是同一个对象实例,才能被认为是相等的
console.log(objIndex) //-1

flat

//用于将一个嵌套数组扁平化为一维数组。可以指定扁平化的深度,默认情况下深度为 1,只会展开一层嵌套的数组。
//通过传递一个数字作为参数,可以控制展开的深度。如果传入 Infinity,则会展开所有层级的嵌套数组。
const nestedArray = [1, [2, 3], 4, [5, [6, 7]]]
const flatArray = nestedArray.flat()
console.log(flatArray)

const deeplyNestedArray = [1, [2, [3, [4, 5]]]]
const flatArray1 = deeplyNestedArray.flat(2) // 指定深度的扁平化,深度为2
console.log(flatArray1)

const deeplyNestedArray1 = [1, [2, [3, [4, 5]]]]
const flatArray2 = deeplyNestedArray1.flat(Infinity) //完全扁平化
console.log(flatArray2);

flatMap

//用于将一个数组映射到另一个数组,并且可以通过返回的映射结果展平最终的数组。
//接受一个映射函数作为参数,该函数可以返回一个数组,而 flatMap() 会自动展平这个数组。默认情况下,展平的深度为 1
//这个方法结合了 map() 和 flat() 方法的功能,使得可以一次性完成映射和扁平化操作。
const numbers = [1, 2, 3]
const doubled = numbers.flatMap(n => [n * 2])
console.log(doubled) //  [2, 4, 6]

const nestedNumbers = [1, [2, 3], 4]
const flatMapped = nestedNumbers.flatMap(n => Array.isArray(n) ? n : [n]) //映射并展平数组
console.log(flatMapped) // [1, 2, 3, 4]

const deeplyNestedNumbers = [1, [2, [3, 4]], 5, [6, [7, [8,9] ] ] ]
const flatMapped1 = deeplyNestedNumbers.flatMap(n => 
  Array.isArray(n) ? n.flatMap(n => n) : [n]) //映射并展平多层嵌套数组,这里深度是2
console.log(flatMapped1) // [1, 2, 3, 4, 5, 6, 7, [8,9] ]

copyWithin

//用于将数组的一部分复制到数组的另一部分,会改变原数组,返回值是复制后的数组。这个方法不改变数组的长度,只是重新排列数组中的元素,例如实现数组的旋转、元素的移动或重复等操作。
//方法接受三个参数:target: 目标索引,即将要放置复制元素的起始位置。start: 可选参数,表示开始复制的索引,默认为 0。end: 可选参数,表示结束复制的索引,默认为数组的长度。
const arr = [1, 2, 3, 4, 5]
const res = arr.copyWithin(0, 2) // 默认从索引 2 开始复制,直到数组末尾
console.log(arr) // [3, 4, 5, 4, 5]
console.log(res) // [3, 4, 5, 4, 5]

const arr1 = [1, 2, 3, 4, 5]
arr1.copyWithin(0, 3, 5)
console.log(arr1) // [4, 5, 3, 4, 5]

const arr2 = [1, 2, 3, 4, 5]
arr2.copyWithin(0, 2, 5) //旋转数组
console.log(arr2) // [3, 4, 5, 4, 5]

const arr3 = [1, 2, 3, 4, 5]
arr3.copyWithin(-3, -5, -2) //使用负数索引
console.log(arr3) // [1, 2, 1, 2, 3]

toString

//将数组转换为字符串,不会改变原数组,返回值是字符串
const arr = [1, 2, 3, 4]
const res = arr.toString()
console.log(res) // 1,2,3,4

const objArr = [{ name: '张三', age: 18 },{ name: '李四', age: 19 }]
const res1 = objArr.toString()
console.log(res1) //[object Object],[object Object] 
/*原因:toString() 方法默认遍历数组中的每个元素并调用每个元素的 toString() 方法。
对于原始类型(如字符串、数字、布尔值)和空数组,toString() 方法会返回一个相应的字符串表示。
但对于对象,默认的 toString() 方法返回的是 [object Object],这是因为对象的 toString() 方法默认实现就是返回这样一个字符串。
*/
//应该使用JSON.stringify()方法去转换复杂数据类型
const objArr1 = [{ name: '张三', age: 18 }, { name: '李四', age: 19 }];
const res2 = JSON.stringify(objArr1);
console.log(res2) // '[{"name":"张三","age":18},{"name":"李四","age":19}]'

toLocaleString

//将数组转换为一个适合当前语言环境的字符串。它与 toString() 方法类似,但toLocaleString() 方法可以根据当前的地区设置(locale)和指定的格式选项(如货币、日期格式等)来格式化数组中的元素
const numbers = [123456.789, 98765.432]
const localeStr = numbers.toLocaleString() //格式化数字数组
console.log(localeStr) //123,456.79,987,654.43

const dates = [new Date(), new Date()]
const localeStr1 = dates.toLocaleString() //格式化日期数组
console.log(localeStr1) //2023/4/6, 10:0:0, 2023/4/6, 10:0:0

const mixed = [123456, new Date()]
const localeStr2 = mixed.toLocaleString() //格式化包含数字和日期的混合数组
console.log(localeStr2) //123,456, 2023/4/6, 10:0:0

const numbers2 = [123456.789, 98765.432]
const localeStr3 = numbers.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' }) //指定地区设置和选项
console.log(localeStr3) //123.456,79 €, 987.654,43 €

const people = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 }
  ]
  const localeStr4 = people.toLocaleString() //格式化包含自定义对象的数组
  console.log(localeStr4) //[Object, Object], [Object, Object]

entries

//用于返回一个迭代器对象,该对象包含了数组中每个元素的索引和值。这个方法特别适用于需要同时访问数组元素的索引和值的情况,通常与 for...of 循环配合使用。
const arr = [10, 20, 30, 40]
console.log(arr.entries()) // Array Iterator { 0 => 10, 1 => 20, 2 => 30, 3 => 40 }
for (const [index, value] of arr.entries()) {
  console.log(`索引: ${index}, 值: ${value}`) //遍历数组并同时获取索引和值
}
// 输出:
// 索引: 0, 值: 10
// 索引: 1, 值: 20
// 索引: 2, 值: 30
// 索引: 3, 值: 40

const arr1 = [1, 2, 3];
const res = [...arr1.entries()].map(([index, value]) => ({ index, value })) //数组映射操作:
console.log(res) // [{ index: 0, value: 1 }, { index: 1, value: 2 }, { index: 2, value: 3 }]

const arr2 = [1, 2, 3];
const res1 = [...arr2.entries()] //创建键值对数组
console.log(res1) // [[0, 1], [1, 2], [2, 3]]

keys

//用于返回一个迭代器对象,该对象包含了数组的每一个索引(key)。这个方法适用于需要迭代数组的索引,而不关心数组元素本身的场景
const arr = [10, 20, 30]
const keys = [...arr.keys()]
console.log(keys) // [0, 1, 2]

const fruits = ['apple', 'banana', 'cherry']
for (const key of fruits.keys()) {
  console.log(key)
}
// 输出:
// 0
// 1
// 2

const arr1 = [1, 2, 3]
const res = arr1.keys().map((key, index) => [key, arr1[index]]) //创建键值对数组
console.log(res) //[[0, 1], [1, 2], [2, 3]]

values

//用于返回一个迭代器对象,该对象包含了数组中的每个元素。这个方法允许你以迭代的方式访问数组中的所有值,通常与 for...of 循环结合使用
const fruits = ['apple', 'banana', 'cherry']
console.log(fruits.values()) // ArrayIterator { 'apple', 'banana', 'cherry' }
for (const fruit of fruits.values()) {
  console.log(fruit) //遍历数组元素
}
// 输出:
// apple
// banana
// cherry

const arr = [1, 2, 3, 4]
const iterator = arr.values() //将数组转换为迭代器并使用
console.log(iterator.next().value) // 1
console.log(iterator.next().value) //  2

const numbers = [1, 2, 3]
const values = Array.from(numbers.values()) //与 Array.from() 结合使用
console.log(values)// [1, 2, 3]

at

//用于获取数组中指定索引位置的元素,可以接受负数索引,在处理不确定长度的数组时,能够更安全地获取元素。
const arr = [1, 2, 3, 4, 5]
const first = arr.at(0) // 获取第一个元素
const last = arr.at(-1) // 获取最后一个元素
console.log(first, last) //  1 5

const secondLast = numbers.at(-2); // 获取倒数第二个元素
console.log(secondLast); //  4

const element = arr.at(10); // 索引超出范围
console.log(element) // undefined

数组静态方法

Array.isArray

//判断一个值是否是数组,返回值是布尔值
const arr = [1, 2, 3]
console.log(Array.isArray(arr)) //true
const str = 'hello'
console.log(Array.isArray(str)) //false

Array.of

//用于创建新数组实例的静态方法。它接受任意数量的参数,并将这些参数作为数组的元素返回一个新的数组。
const arr = Array.of()
console.log(arr) // []

const arr1 = Array.of(42)
console.log(arr1) //  [42]

const arr2 = Array.of(1, 'two', true, null, undefined, { key: 'value' }, [1, 2, 3])
console.log(arr2) //  [1, 'two', true, null, undefined, { key: 'value' }, [1, 2, 3]]

Array.from

//用于从类数组对象或可迭代对象创建一个新的数组实例。
//可以接受一个映射函数作为第二个参数,允许你在创建数组的同时对数组的每个元素进行转换。此外,还可以传递一个 thisArg 参数来指定映射函数内部的 this 值。
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }
const array = Array.from(arrayLike) //从类数组对象创建数组
console.log(array) // ['a', 'b', 'c']

const str = 'hello'
const charArray = Array.from(str) //从字符串创建数组
console.log(charArray) //  ['h', 'e', 'l', 'l', 'o']

const set = new Set(['a', 'b', 'c'])
const arrayFromSet = Array.from(set) //从 Set 创建数组:
console.log(arrayFromSet) //  ['a', 'b', 'c']

const map = new Map([[1, 'one'], [2, 'two']])
const arrayFromMapKeys = Array.from(map.keys()) //从 Map 创建数组:
console.log(arrayFromMapKeys)//  [1, 2]

const numbers = [1, 2, 3, 4, 5]
const doubled = Array.from(numbers, n => n * 2) //使用映射函数创建数组
console.log(doubled) // [2, 4, 6, 8, 10] 

const obj = {
    multiplyByTwo: function (n) {
        return n * 2
    }
}
const arr = [1, 2, 3, 4, 5]
const doubled1 = Array.from(arr, obj.multiplyByTwo, obj) //使用 thisArg 参数:
console.log(doubled1) // [2, 4, 6, 8, 10]

const filledArray = Array.from({ length : 5 }, (_, index) => index) //创建特定长度的数组并填充
console.log(filledArray);// [0, 1, 2, 3, 4]

生成数组的方法

//1.直接初始化数组:
const arr1 = [1, 2, 3];

//2.使用 new Array() 构造函数:
const arr2 = new Array(1, 2, 3);

//3.Array.of() 方法:
const arr3 = Array.of(1, 2, 3);

//4.使用 Array.from() 方法:
//4.1从类数组或可迭代对象创建数组:
const arr4 = Array.from({ length: 5 }, (_, i) => i + 1); // [1, 2, 3, 4, 5]
//4.2从字符串创建数组:
const str = 'hello';
const arr5 = Array.from(str); // ['h', 'e', 'l', 'l', 'o']

//5.使用扩展运算符 (...):
const arr6 = [...'hello']; // ['h', 'e', 'l', 'l', 'o']

//6.使用 Array.fill() 方法:
const arr7 = new Array(5).fill(0); // [0, 0, 0, 0, 0]

//7.使用 Array.from() 和 Array.of() 结合 map() 方法:
const arr8 = Array.from({ length: 5 }, () => Math.random());

//8.使用 Array.from() 和索引映射:
const arr9 = Array.from({ length: 5 }, (_, i) => i * 2); // [0, 2, 4, 6, 8]

//9.使用 Array.from() 和 Number.call:
const arr01 = Array.from({ length: 5 }, Number.call, Number); // [0, 1, 2, 3, 4]

//10.使用 Array.from() 和 Function.call:
const arr02 = Array.from({ length: 5 }, Function.call, Number); // [0, 1, 2, 3, 4]

//11.使用 Array.from() 和 Array.prototype.map:
const arr03 = Array.from({ length: 5 }, Array.prototype.map, [i => i * 2]);

//12.使用 Array.from() 和 Function.apply:
const arr04 = Array.from({ length: 5 }, Function.apply, [Number, []]); // [0, 1, 2, 3, 4]

//13.使用 Array.from() 和 Function.bind:
const arr05 = Array.from({ length: 5 }, Function.bind.call(Number, undefined));

判断数组的方法

console.log ( Array.isArray([1,2,3])) // true
console.log ( typeof [1,2,3]) // object
console.log( [1,2,3] instanceof Array) // true
console.log(Array.prototype.isPrototypeOf([1,2,3])) // true
console.log(Object.prototype.toString.call([1,2,3]) === '[object Array]') // true
console.log([1,2,3].constructor === Array) // true

//Array.prototype.isPrototypeOf() 和 instanceof 都依赖于对象的原型链。如果原型链被污染,那么这两种方法的结果可能会受到影响。

/**什么是原型链污染?
 * 
 * 原型链污染指的是攻击者能够修改对象原型上的属性,从而影响到其他对象的行为。
 * 这通常发生在 Web 应用程序中,当用户提供的数据被不当处理并最终用于修改全局对象的原型时,就会发生原型链污染。
 * 
 */

/**原型链污染的影响
 * 
 * 属性覆盖:攻击者可以通过修改原型上的属性来覆盖现有的属性值。
 * 例如,如果攻击者能够将 Array.prototype.length 设置为一个恶意值,那么所有数组实例的 length 属性都会受到影响。
 * 
 * 方法替换:攻击者可以替换原型上的方法,导致原本的方法行为被改变。
 * 例如,如果攻击者将 Array.prototype.push 替换为一个恶意函数,那么所有的 push 调用都将执行恶意代码而不是预期的行为。
 * 
 * 添加新属性或方法:攻击者可以在原型上添加新的属性或方法,这些属性或方法会被所有继承该原型的对象共享。
 * 例如,如果攻击者在 Array.prototype 上添加了一个恶意方法 pollutedMethod,那么所有数组实例都可以访问并调用这个方法。
 * 
 */

/**当原型链受到污染时,它可能会影响以下方面
 * 
 * 下面是一个简单的示例来展示原型链污染如何改变值:
 *  创建一个正常的数组
 * let arr = [1, 2, 3];
 * 
 * 输出数组的原始长度
 * console.log(arr.length); // 3
 * 
 * 模拟原型链污染
 * Array.prototype.length = 999;
 * 
 *  输出数组的新长度
 * console.log(arr.length); // 999
 * 
 * 在这个例子中,通过修改 Array.prototype.length 将所有数组实例的 length 属性都改为了 999。
 * 
*/

/**防止原型链污染的措施
 * 
 * 使用 Object.freeze() 冻结对象,使其不能被修改。
 * 例如,可以冻结 Array.prototype 来防止它被修改。
 * 
 * 对用户提供的数据进行严格的验证,确保它们不会被用于修改原型。
 * 例如,使用白名单或黑名单策略来过滤掉潜在的恶意输入。
 * 
 * 可以考虑使用 Map 或 WeakMap 来替代普通的对象,因为它们提供了更好的安全性和隔离性。
 * 
 * 定期检查和更新你使用的第三方库,确保它们没有已知的安全漏洞。
 * 
 */

数组的解构赋值

//基础用法
const a = 1
const b = 2
const c = 3
//等同于
const [a,b,c] = [1,2,3]

const [a] = []
console.log(a)//undefined

const [a,b] = [1,2,3]
console.log(a,b)//1,2

const [a,,c] = [1,2,3]
console.log(a,c)//1,3

const [a,b,c] = [1,2]
console.log(a,b,c)//1,2,undefined

const [a,[b],c] = [1,[2,3],4]
console.log(a,b,c)//1,[2],4

const [a,...b] = [1,2,3,4,5]
console.log(a,b) //1,[2,3,4,5]

const [a,b,...c] = [1]
console.log(a,b,c) //1,undefined,[]

//默认值,只有当一个数组成员严格等于undefined,默认值才会生效
const [a,b=2,c] = [1]
console.log(a,b,c) //1,2,undefined

const [a,b=2,c] = [1,undefined,3]
console.log(a,b,c) //1,2,3 

const [a,b=2,c] = [1,null,3]
console.log(a,b,c) //1,null,3

//默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
const [x = 1, y = x] = [];     // x=1; y=1
const [x = 1, y = x] = [2];    // x=2; y=2
const [x = 1, y = x] = [1, 2]; // x=1; y=2
const [x = y, y = 1] = [];     // ReferenceError: y is not defined ,因为x用y做默认值时,y还没有声明。

//函数参数解构
function add([x,y]){
    console.log(x+y)
}
add([1,2,3]) //3