07数组。

本文详细介绍了JavaScript中的数组,包括如何创建和添加元素,数组的遍历方式,如for循环和for...of,以及数组的各种方法如concat、indexOf、lastIndexOf、join、slice等。此外,还讨论了浅拷贝和深拷贝的概念及实现,并提供了数组去重和排序的示例代码。
摘要由CSDN通过智能技术生成

数组

*数组的简介

//创建一个数组:
//1.使用Array()的构造函数来创建数组
const arr = new Array()
//2.使用字面量创建一个数组
let arr2 = []
//向数组中添加元素
//1.通过索引向数组中添加数据
arr[0] = 10
arr[1] = 20
//2.直接在字面量中添加元素
arr2 = [1, 2, 3, 4, 100]
//不连续数组: (使用数组时, 尽量避免不连续数组)
arr[100] = 100
//读取数组
console.log(arr[0]) // 10
console.log(arr2[2])// 3
console.log(arr2[1000]) //undefined
console.log(typeof arr) //object
console.log(typeof arr2) //object
//使用length获取数组的长度
console.log(arr.length)
//使用length向数组最后添加元素
arr[arr.length] = 33
//使用length修改数组的长度
arr.length = 5
console.log(arr)

数组: 数组与对象一样也是复合数据类型, 在数组中可以存储多个不同类型的数据(元素), 数组中存储的是有序数据, 而对象中存储的是无序的数据, 数组中的每个数据都有唯一的一个索引, 可以通过索引来操作, 获取数据

索引(index): 一组大于0, 且从0开始的整数, 读取数组中不存在的元素时, 不会报错, 而是返回undefined, 使用typeof检查数组会返回Object

*数组的遍历

使用for循环遍历数组

//任何类型的值都可以作为数组的元素 (尽量储存同类型的值)
const arr = [1, "String", true, null, {name: "张三"}, () => {console.log(11)}]
const arr2 = ["张三", "李四", "汤姆", "杰克"]
//可以使用for循环遍历数组
//正向遍历
for (let i=0; i<arr2.length; i++) {
  console.log(arr2[i])
}
//反向遍历
for (let i=arr2.length-1; i>=0; i--) {
  console.log(arr2[i])
}

//小练习--打印成年人与未成年人
class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
  }
}
const personArr = [
        new Person("张三", 49),
        new Person("李四", 50),
        new Person("杰克", 17),
        new Person("汤姆", 5),
]
console.log(personArr[0].age)
for(let i=0; i<personArr.length; i++) {
  if(personArr[i].age>=18) {
    console.log(personArr[i].name + "成年")
  }else {
    console.log(personArr[i].name + "未成年")
  }
}

使用for of遍历数组

const arr2 = ["张三", "李四", "汤姆", "杰克"]
//使用for in遍历数组
for(let value of arr2) {
  console.log(value)
}
//for of 可以遍历 可迭代对象(有下标的对象: 例如:数组, 字符串)
for(let v of "hello") {
  console.log(v)
}

*数组的方法(非破坏性)

console.log(Array.isArray({name: "张三"})) //false
console.log(Array.isArray([1, 2, 3])) //true
const arr = ["张三", "李四", "汤姆", "杰克"]
const arr2 = [1, 2, 3, 4]
console.log(arr.at(1))//"李四"
console.log(arr.at(-3))//"李四"

let result = arr.concat(arr2, ["fk", "fkAll"])
console.log(result)

静态方法:
Array.isArray()

  • 用来检查一个对象是否为数组

实例方法:
at()

  • 可以根据索引获取数组中的指定元素
  • at 可以接收负值做引作为参数, 即获取倒数第几个元素

concat()

  • 用来链接两个或者多个数组
  • 非破坏方法, 即不会影响旧数组, 而是返回一个新数组
const arr = ["张三", "李四", "汤姆", "张三", "李四", "杰克"]
//indexOf()
let result = arr.indexOf("张三") //0
let result2 = arr.indexOf("张三", 4) //从索引4的元素开始 往后查询, 查询不到返回 -1
console.log(result, result2)
//lastIndexOf()
let r = arr.lastIndexOf("张三") //3
let r2 = arr.lastIndexOf("张三", 0) //从索引0元素开始 往前查询, 第一个"张三"刚好位于索引0
console.log(r, r2)
//join()
let j = arr.join()//默认连接符号为 , 号
j = arr.join("╰(*°▽°*)╯") //指定 ╰(*°▽°*)╯ 为连接符号
console.log(j)
//slice()
let s = arr.slice(0, 1) // 张三
let s2 = arr.slice(0, -1) // "张三", "李四", "汤姆", "张三", "李四"
let s3 = arr.slice() // "张三", "李四", "汤姆", "张三", "李四"
console.log(s, s2, s3)

indexOf()

  • 获取元素在数组中第一次出现的索引, 可以指定开始查询的位置 – (从前往后查), 返回值: 查询到则返回元素索引, 否则返回-1

lastIndexOf()

  • 与indexOf使用方法类似, 查询顺序改为 从后往前查

join()

  • 将一个数组中的元素连接成一个 字符串, 可以自定字符串的连接符号

slice()

  • 截取数组, 包括起始位置, 不包括结束位置, 不写截取结束位置, 则一直截取到最后一个元素
  • 可以传递负值, 从后往前数 , 如果不写开始位置与结束位置, 则截取全部 即 (浅拷贝)

**浅拷贝与深拷贝

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uM8qpGEL-1672792016108)(https://raw.githubusercontent.com/ehco666/to-picgo/main/img/202209172132631.png)]

https://raw.githubusercontent.com/ehco666/to-picgo/main/img/202209172132631.png

const arr = [{name: "张三"}, {name: "李四"}]
//浅拷贝
const arr2 = arr.slice()
console.log(arr2 === arr) //false
arr2[0].name = "hello"
console.log(arr, arr2) //浅拷贝: 修改拷贝后的对象属性(,元素) 会对拷贝前的对象产生影响
//深拷贝
//structuredClone() -- 针对深拷贝	
const arr3 = structuredClone(arr)
console.log(arr3 === arr) //false
arr3[0] = "world"
console.log(arr, arr3)//深拷贝: 修改拷贝后的对象属性(,元素) 不会对拷贝前的对象产生影响

浅拷贝(shallow copy):

  • 通常对对象的拷贝都是浅拷贝
  • 浅拷贝只会对 对象拷贝一层, 即对对象本身进行拷贝, 不会拷贝对象中的属性(或者元素)

深拷贝(deep copy):

  • 深拷贝不仅拷贝对象本身, 还拷贝对象的属性(或者元素)
  • 通常情况下不使用深拷贝,(存在性能问题)

注意: 对象中存储的数据是原始值时, 没有浅拷贝与深拷贝的区别

拷贝的方法

//数组的拷贝
const arr = ["张三", "李四", "瑞克", "莫蒂"]
//1.手动浅拷贝
let arr2 = [arr[0], arr[1], arr[2], arr[3]]
// ...(展开运算符)
arr2 = [...arr]
console.log(arr, arr2)
//展开运算符作为函数的参数传递
function sum(a, b, c) {
  return a + b + c
}
const a = [10, 20 ,30]
console.log(sum(...a))
//对象的拷贝
//1.静态属性 Object.assign()
const obj = {name: "张三", age: 18}
const obj2 = {address: "高老庄", age: 48}
Object.assign(obj2, obj) //将对象obj拷贝到obj2中, age被obj的age覆盖
console.log(obj, obj2)
//2.展开运算符 ...()
const obj3 = {address: "流沙河", ...obj, age: 50} //将obj中的属性展开到obj3中, age在展开运算符后面, 不会被覆盖
console.log(obj, obj3)

浅拷贝的方法:

  • 数组
  1. 手动拷贝
  2. slice()方法
  3. …() 展开运算符 – 使一个数组||对象, 展开到另个一数组||对象中
  • 对象
  1. Object.assign() – 将一个对象拷贝到目标对象, 并将目标对象返回, 同名属性将被覆盖
  2. …() 展开运算符

数组的方法(破坏性)

const arr = ["莫蒂","杰克", "瑞克", "汤姆"]
let result = arr.push("张三", "李四")
console.log(arr)
console.log(result) //返回新数组的长度 6
let result2 = arr.pop()
console.log(arr)
console.log(result2) //返回删除的元素
let result3 = arr.unshift("kt")
console.log(arr)
console.log(result3) //返回新数组的长度 6
let result4 = arr.shift()
console.log(arr)
console.log(result4) //返回删除的元素
let r
//删除
r = arr.splice(1, 2)
console.log(r)
console.log(arr)
//添加, 插入
r = arr.splice(1, 0, "cr1", "cr2")
console.log(r)
console.log(arr)
//替换
r = arr.splice(1, 1, "th1", "th2")
console.log(r);
console.log(arr)
const arr2 = [1, 2, 3, 4, 5]
arr2.reverse()
console.log(arr2)

数组的方法(破坏性):
push()

  • 向数组末尾添加一个或多个元素, 并返回新数组的长度

pop()

  • 删除并返回数组的最后一个元素

unshift()

  • 向数组开头添加一个或多个元素, 并返回新数组的长度

shift()

  • 删除并返回数组的第一个元素

splice() -- 功能强大, 比较常用

  • 删除, 添加, 插入, 替换, 数组中的元素, 返回删除的元素

  • 参数

    1. 删除的起始位置
    2. 删除的数量
    3. 插入的元素

reverse()

  • 反转数组

*练习: 数组去重

const a = [1, 2, 1, 3, 2, 2, 2, 4, 5, 5, 6, 7, 7, 7]
//方式一
// //获取数组中的元素
// for(let i=0; i<a.length; i++) {
//   //获取索引i后面的所有元素
//   for(let j=i+1; j<a.length; j++) {
//     if(a[i] === a[j]) {
//       //删除索引j对应的元素
//       a.splice(j, 1)
//       j-- // 回退一个索引,在进行比较, 方式漏删
//     }
//   }
// }
// console.log(a)
//方式二
// for(let i=0; i<a.length; i++) {
//   const index = a.indexOf(a[i], i+1)
//   if(index !== -1) {
//     console.log(i, index)
//     a.splice(index, 1)
//     i--
//   }
// }
// console.log(a)
//方式三
let n = []
for(let ele of a) {
  if(n.indexOf(ele) === -1) {
    n.push(ele)
  }
}
console.log(n)

思路1: 破坏性方法, 在原数组上删除重复的元素–> 方式1, 2

思路2: 非破坏性方法, 创建新的数组, 把原数组的元素添加到新数组, 判断重复的元素使其不会添加到新数组里

*练习: 数组排序

冒泡排序

//冒泡排序
//思路 : 比较相邻两个元素的大小, 然后根据大小进行排序
const arr = [9, 1, 3, 2, 8, 0, 5, 7, 6, 4]
for(let i=0; i<arr.length-1; i++) {
  // console.log(i)
  for (let j=0; j<arr.length-i-1; j++) { //后面的值不用再进行比较, 因此数组长度减去 i
    console.log(i, "-->" +  j)
    if (arr[j] < arr[j+1]) {
      let temp = arr[j+1]
      arr[j+1] = arr[j]
      arr[j] = temp
    }
  }
}
console.log(arr)

选择排序

// 选择排序
// 思路 : 选择一个元素, 与其他元素进行对比, 如果比它小就进行交换
const arr2 = [9, 1, 3, 2, 8, 0, 5, 7, 6, 4]
for (let i=0; i<arr2.length; i++) {
  for (let j=i+1; j<arr2.length; j++) {
    // 每次交换位置以后, arr2[i]的元素都会改变, 并不是一直都为9
    if (arr2[i] > arr2[j]) {
      let temp = arr2[j]
      arr2[j] = arr2[i]
      arr2[i] = temp
    }
  }
}
console.log(arr2)

以上两种排序方法, 性能都比较差, 只适用于元素比较少的数组, 但排序的逻辑要掌握清楚

**封装函数

封装一 :

const arr2 = [9, 1, 3, 2, 8, 0, 5, 7, 6, 4]
function short(al) {
    const a = [...al]// 转成非破坏性
    for (let i=0; i<a.length; i++) {
  		for (let j=i+1; j<a.length; j++) {
    	if (a[i] > a[j]) {
      	let temp = a[j]
      	a[j] = a[i]
      	a[i] = temp
    		}
 	 	}
	}
    return a
}
let result = short(arr2)
console.log(result)
console.log(arr2)

封装二 :

class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
  }
}
const personArr = [
        new Person("张三", 49),
        new Person("李四", 50),
        new Person("杰克", 17),
        new Person("汤姆", 5),
]
function filter(arr) {
//小练习--输出未成年人
    const a = []
	for(let i=0; i<arr.length; i++) {
  	if(arr[i].age>=18) {
   	 	console.log(arr[i].name + "成年")
  	}else {
    	a.push(arr[i])
  		}
	}
    return a
}
let result = filter(personArr)
console.log(result)

封装三(修改封装二, 使其功能更加完善) :

class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
  }
}
const personArr = [
        new Person("张三", 49),
        new Person("李四", 50),
        new Person("杰克", 17),
        new Person("汤姆", 5),
]
function filter(arr, cb) { //2.cb形参,接受传递的fn(函数)实参, 
    const a = []
	for(let i=0; i<arr.length; i++) {
     	//3.cb() 调用传入的实参即: 调用fn --> fn()(回调函数调用), 并传递实参 arr[i]
  	if( cb(arr[i]) ) { 
    	a.push(arr[i])
  		}
	}
    return a
}
function fn(f) { //4.定义函数 fn(回调函数), f形参, 接受传递的 arr[i](数组) 实参
    //return f.name === "张三" //返回name是张三的元素(对象)
    //return f.age > 18 //返回age大于18的元素(对象)
    return f.age === 5 //返回age等于5的元素(对象)
}
let result = filter(personArr, fn) //1.fn实参,传递fn函数
console.log(result)

一个函数的参数也可以是函数, 即 回调函数

i<arr.length; i++) {
//3.cb() 调用传入的实参即: 调用fn --> fn()(回调函数调用), 并传递实参 arr[i]
if( cb(arr[i]) ) {
a.push(arr[i])
}
}
return a
}
function fn(f) { //4.定义函数 fn(回调函数), f形参, 接受传递的 arri 实参
//return f.name === “张三” //返回name是张三的元素(对象)
//return f.age > 18 //返回age大于18的元素(对象)
return f.age === 5 //返回age等于5的元素(对象)
}
let result = filter(personArr, fn) //1.fn实参,传递fn函数
console.log(result)


> 一个函数的参数也可以是函数,	即 **回调函数**
>
> 回调函数:	定义函数后, 在别的函数里进行调用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值