(六)数组 - 图1

数组

  • 什么是数组?
  • 字面理解就是 数字的组合
  • 其实不太准确,准确的来说数组是一个 数据的集合
  • 也就是我们把一些数据放在一个盒子里面,按照顺序排好

    1. [1, 2, 3, 'hello', true, false]
  • 这个东西就是一个数组,存储着一些数据的集合

数据类型分类

  • number / string / boolean / undefined / null / object / function / array / …
  • 数组也是数据类型中的一种
  • 我们简单的把所有数据类型分为两个大类 基本数据类型复杂数据类型
  • 基本数据类型: number / string / boolean / undefined / null
  • 复杂数据类型: object / function / array / …

创建一个数组

  • 数组就是一个 []
  • [] 里面存储着各种各样的数据,按照顺序依次排好

字面量创建一个数组

  • 直接使用 [] 的方式创建一个数组 ```javascript // 创建一个空数组 var arr1 = []

// 创建一个有内容的数组 var arr2 = [1, 2, 3]

  1. <a name="14abffbc"></a>
  2. ### 内置构造函数创建数组
  3. - 使用 js 的内置构造函数 `Array` 创建一个数组
  4. ```javascript
  5. // 创建一个空数组
  6. var arr1 = new Array()
  7. // 创建一个长度为 10 的数组
  8. var arr2 = new Array(10)
  9. // 创建一个有内容的数组
  10. var arr3 = new Array(1, 2, 3)

数组的 length

  • length: 长度的意思
  • length 就是表示数组的长度,数组里面有多少个成员,length 就是多少 ```javascript // 创建一个数组 var arr = [1, 2, 3]

console.log(arr.length) // 3

  1. <a name="026a10a3"></a>
  2. ### 数组的索引
  3. - 索引,也叫做下标,是指一个数据在数组里面排在第几个的位置
  4. - 注意: **在所有的语言里面,索引都是从 0 开始的**
  5. - 在 js 里面也一样,数组的索引从 0 开始
  6. ```javascript
  7. // 创建一个数组
  8. var arr = ['hello', 'world']
  • 上面这个数组中,第 0 个 数据就是字符串 hello第 1 个 数据就是字符串 world
  • 想获取数组中的第几个就使用 数组[索引] 来获取 ```javascript var arr = [‘hello’, ‘world’]

console.log(arr[0]) // hello console.log(arr[1]) // world

  1. <a name="f871cf58"></a>
  2. ## 数据类型之间存储的区别(重点)
  3. - 既然我们区分了基本数据类型和复杂数据类型
  4. - 那么他们之间就一定会存在一些区别
  5. - 他们最大的区别就是在存储上的区别
  6. - 我们的存储空间分成两种 **栈** 和 **堆**
  7. - 栈: 主要存储基本数据类型的内容
  8. - 堆: 主要存储复杂数据类型的内容
  9. <a name="1a6afeef"></a>
  10. ### 基本数据类型在内存中的存储情况
  11. - `var num = 100`,在内存中的存储情况
  12. - ![](https://note.youdao.com/yws/res/9219/086FC0F7370A48FFB98F83B2C1392272#id=NxXD9&originalType=binary&ratio=1&status=done&style=none)
  13. - 直接在 **栈空间** 内有存储一个数据
  14. <a name="24b0be82"></a>
  15. ### 复杂数据类型在内存中的存储情况
  16. - 下面这个 对象 的存储
  17. ```javascript
  18. var obj = {
  19. name: 'Jack',
  20. age: 18,
  21. gender: '男'
  22. }
  • (六)数组 - 图2
  • 复杂数据类型的存储
    1. 在堆里面开辟一个存储空间
    2. 把数据存储到存储空间内
    3. 把存储空间的地址赋值给栈里面的变量
  • 这就是数据类型之间存储的区别

数据类型之间的比较

  • 基本数据类型是 之间的比较 ```javascript var num = 1 var str = ‘1’

console.log(num == str) // true

  1. - 复杂数据类型是 **地址** 之间的比较
  2. ```javascript
  3. var obj = { name: 'Jack' }
  4. var obj2 = { name: 'Jack' }
  5. console.log(obj == obj2) // false
  • 因为我们创建了两个对象,那么就会在 堆空间 里面开辟两个存储空间存储数据(两个地址)
  • 虽然存储的内容是一样的,那么也是两个存储空间,两个地址
  • 复杂数据类型之间就是地址的比较,所以 objobj2 两个变量的地址不一样
  • 所以我们得到的就是 false

数组的常用方法

  • 数组是一个复杂数据类型,我们在操作它的时候就不能再想基本数据类型一样操作了
  • 比如我们想改变一个数组 ```javascript // 创建一个数组 var arr = [1, 2, 3]

// 我们想把数组变成只有 1 和 2 arr = [1, 2]

  1. - 这样肯定是不合理,因为这样不是在改变之前的数组
  2. - 相当于心弄了一个数组给到 arr 这个变量了
  3. - 相当于把 arr 里面存储的地址给换了,也就是把存储空间换掉了,而不是在之前的空间里面修改
  4. - 所以我们就需要借助一些方法,在不改变存储空间的情况下,把存储空间里面的数据改变了
  5. <a name="ac8c24a1"></a>
  6. ### 数组常用方法之 push
  7. - `push` 是用来在数组的末尾追加一个元素
  8. ```javascript
  9. var arr = [1, 2, 3]
  10. // 使用 push 方法追加一个元素在末尾
  11. arr.push(4)
  12. console.log(arr) // [1, 2, 3, 4]

数组常用方法之 pop

  • pop 是用来删除数组末尾的一个元素 ```javascript var arr = [1, 2, 3]

// 使用 pop 方法删除末尾的一个元素 arr.pop()

console.log(arr) // [1, 2]

  1. <a name="1d1fcf44"></a>
  2. ### 数组常用方法之 unshift
  3. - `unshift` 是在数组的最前面添加一个元素
  4. ```javascript
  5. var arr = [1, 2, 3]
  6. // 使用 unshift 方法想数组的最前面添加一个元素
  7. arr.unshift(4)
  8. console.log(arr) // [4, 1, 2, 3]

数组常用方法之 shift

  • shift 是删除数组最前面的一个元素 ```javascript var arr = [1, 2, 3]

// 使用 shift 方法删除数组最前面的一个元素 arr.shift()

console.log(arr) // [2, 3]

  1. <a name="777315c2"></a>
  2. ### 数组常用方法之 splice
  3. - `splice` 是截取数组中的某些内容,按照数组的索引来截取
  4. - 语法: `splice(从哪一个索引位置开始,截取多少个,替换的新元素)` (第三个参数可以不写)
  5. ```javascript
  6. var arr = [1, 2, 3, 4, 5]
  7. // 使用 splice 方法截取数组
  8. arr.splice(1, 2)
  9. console.log(arr) // [1, 4, 5]
  • arr.splice(1, 2) 表示从索引 1 开始截取 2 个内容
  • 第三个参数没有写,就是没有新内容替换掉截取位置 ```javascript var arr = [1, 2, 3, 4, 5]

// 使用 splice 方法截取数组 arr.splice(1, 2, ‘我是新内容’)

console.log(arr) // [1, ‘我是新内容’, 4, 5]

  1. - `arr.splice(1, 2, '我是新内容')` 表示从索引 1 开始截取 2 个内容
  2. - 然后用第三个参数把截取完空出来的位置填充
  3. <a name="b24bd2f0"></a>
  4. ### 数组常用方法之 reverse
  5. - `reverse` 是用来反转数组使用的
  6. ```javascript
  7. var arr = [1, 2, 3]
  8. // 使用 reverse 方法来反转数组
  9. arr.reverse()
  10. console.log(arr) // [3, 2, 1]

数组常用方法之 sort

  • sort 是用来给数组排序的 ```javascript var arr = [2, 3, 1]

// 使用 sort 方法给数组排序 arr.sort()

console.log(arr) // [1, 2, 3]

  1. - 这个只是一个基本的简单用法
  2. <a name="9a6aea2e"></a>
  3. ### 数组常用方法之 concat
  4. - `concat` 是把多个数组进行拼接
  5. - 和之前的方法有一些不一样的地方,就是 `concat` 不会改变原始数组,而是返回一个新的数组
  6. ```javascript
  7. var arr = [1, 2, 3]
  8. // 使用 concat 方法拼接数组
  9. var newArr = arr.concat([4, 5, 6])
  10. console.log(arr) // [1, 2, 3]
  11. console.log(newArr) // [1, 2, 3, 4, 5, 6]
  • 注意: concat 方法不会改变原始数组

数组常用方法之 join

  • join 是把数组里面的每一项内容链接起来,变成一个字符串
  • 可以自己定义每一项之间链接的内容 join(要以什么内容链接)
  • 不会改变原始数组,而是把链接好的字符串返回 ```javascript var arr = [1, 2, 3]

// 使用 join 链接数组 var str = arr.join(‘-‘)

console.log(arr) // [1, 2, 3] console.log(str) // 1-2-3

  1. - 注意: **join 方法不会改变原始数组,而是返回链接好的字符串**
  2. <a name="8fa365ca"></a>
  3. ## for 和 for in 循环
  4. - 因为数组的索引就可以获取数组中的内容
  5. - 数组的索引又是按照 0 n 顺序排列
  6. - 我们就可以使用 for 循环来循环数组,因为 for 循环我们也可以设置成 0 n 顺序增加
  7. - 我们把这个行为叫做 **遍历**
  8. ```javascript
  9. var arr = [1, 2, 3, 4, 5]
  10. // 使用 for 循环遍历数组
  11. for (var i = 0; i < arr.length; i++) {
  12. console.log(arr[i])
  13. }
  14. // 会在控制台依次打印出 1, 2, 3, 4, 5
  • i < arr.length 因为 length 就是数组的长度,就是一个数字,所以我们可以直接用它来决定循环次数
  • console.log(arr[i]) 因为随着循环,i 的值会从 0 开始依次增加
  • 所以我们实际上就相当于在打印 arr[0] / arr[1] / …
    • 因为 对象 是没有索引的,所以我们没有办法使用 for 循环来遍历
    • 这里我们使用 for in 循环来遍历对象
    • 先来看一段代码 ```javascript var obj = { name: ‘Jack’, age: 18 }

for (var key in obj) { console.log(key) }

// 会在控制台打印两次内容,分别是 name 和 age

  1. - for in 循环的遍历是按照对象中有多少成员来决定了
  2. - 有多少成员,就会执行多少次
  3. - `key` 是我们自己定义的一个变量,就和 for 循环的时候我们定义的 i 一个道理
  4. - 在每次循环的过程中,key 就代表着对象中某一个成员的 **属性名**
  5. <a name="c60ac967"></a>
  6. ## 数组的排序
  7. - 排序,就是把一个乱序的数组,通过我们的处理,让他变成一个有序的数组
  8. - 今天我们讲解两种方式来排序一个数组 **冒泡排序** **选择排序**
  9. <a name="5d7ecc89"></a>
  10. ### 冒泡排序
  11. - 先遍历数组,让挨着的两个进行比较,如果前一个比后一个大,那么就把两个换个位置
  12. - 数组遍历一遍以后,那么最后一个数字就是最大的那个了
  13. - 然后进行第二遍的遍历,还是按照之前的规则,第二大的数字就会跑到倒数第二的位置
  14. - 以此类推,最后就会按照顺序把数组排好了
  15. 1. 我们先来准备一个乱序的数组
  16. ```javascript
  17. var arr = [3, 1, 5, 6, 4, 9, 7, 2, 8]
  1. - 接下来我们就会用代码让数组排序
  1. 先不着急循环,先来看数组里面内容换个位置

    1. // 假定我现在要让数组中的第 0 项和第 1 项换个位置
    2. // 需要借助第三个变量
    3. var tmp = arr[0]
    4. arr[0] = arr[1]
    5. arr[1] = tmp
  2. 第一次遍历数组,把最大的放到最后面去 ```javascript for (var i = 0; i < arr.length; i++) { // 判断,如果数组中的当前一个比后一个大,那么两个交换一下位置 if (arr[i] > arr[i + 1]) { var tmp = arr[i] arr[i] = arr[i + 1] arr[i + 1] = tmp } }

// 遍历完毕以后,数组就会变成 [3, 1, 5, 6, 4, 7, 2, 8, 9]

  1. - 第一次结束以后,数组中的最后一个,就会是最大的那个数字
  2. - 然后我们把上面的这段代码执行多次。数组有多少项就执行多少次
  3. 1. 按照数组的长度来遍历多少次
  4. ```javascript
  5. for (var j = 0; j < arr.length; j++) {
  6. for (var i = 0; i < arr.length; i++) {
  7. // 判断,如果数组中的当前一个比后一个大,那么两个交换一下位置
  8. if (arr[i] > arr[i + 1]) {
  9. var tmp = arr[i]
  10. arr[i] = arr[i + 1]
  11. arr[i + 1] = tmp
  12. }
  13. }
  14. }
  15. // 结束以后,数组就排序好了
  1. 给一些优化

    • 想象一个问题,假设数组长度是 9,第八次排完以后
    • 后面八个数字已经按照顺序排列好了,剩下的那个最小的一定是在最前面
    • 那么第九次就已经没有意义了,因为最小的已经在最前面了,不会再有任何换位置出现了
    • 那么我们第九次遍历就不需要了,所以我们可以减少一次

      1. for (var j = 0; j < arr.length - 1; j++) {
      2. for (var i = 0; i < arr.length; i++) {
      3. // 判断,如果数组中的当前一个比后一个大,那么两个交换一下位置
      4. if (arr[i] > arr[i + 1]) {
      5. var tmp = arr[i]
      6. arr[i] = arr[i + 1]
      7. arr[i + 1] = tmp
      8. }
      9. }
      10. }
    • 第二个问题,第一次的时候,已经把最大的数字放在最后面了

    • 那么第二次的时候,其实倒数第二个和最后一个就不用比了
    • 因为我们就是要把倒数第二大的放在倒数第二的位置,即使比较了,也不会换位置
    • 第三次就要倒数第三个数字就不用再和后两个比较了
    • 以此类推,那么其实每次遍历的时候,就遍历当前次数 - 1 次
      1. for (var j = 0; j < arr.length - 1; j++) {
      2. for (var i = 0; i < arr.length - 1 - j; i++) {
      3. // 判断,如果数组中的当前一个比后一个大,那么两个交换一下位置
      4. if (arr[i] > arr[i + 1]) {
      5. var tmp = arr[i]
      6. arr[i] = arr[i + 1]
      7. arr[i + 1] = tmp
      8. }
      9. }
      10. }
  2. 至此,一个冒泡排序就完成了

选择排序

  • 先假定数组中的第 0 个就是最小的数字的索引
  • 然后遍历数组,只要有一个数字比我小,那么就替换之前记录的索引
  • 知道数组遍历结束后,就能找到最小的那个索引,然后让最小的索引换到第 0 个的位置
  • 再来第二趟遍历,假定第 1 个是最小的数字的索引
  • 在遍历一次数组,找到比我小的那个数字的索引
  • 遍历结束后换个位置
  • 依次类推,也可以把数组排序好

    1. 准备一个数组

      1. var arr = [3, 1, 5, 6, 4, 9, 7, 2, 8]
    2. 假定数组中的第 0 个是最小数字的索引

      1. var minIndex = 0
    3. 遍历数组,判断,只要数字比我小,那么就替换掉原先记录的索引 ```javascript var minIndex = 0 for (var i = 0; i < arr.length; i++) { if (arr[i] < arr[minIndex]) { minIndex = i } }

// 遍历结束后找到最小的索引 // 让第 minIndex 个和第 0 个交换 var tmp = arr[minIndex] arr[minIndex] = arr[0] arr[0] = tmp

  1. 1. 按照数组的长度重复执行上面的代码
  2. ```javascript
  3. for (var j = 0; j < arr.length; j++) {
  4. // 因为第一遍的时候假定第 0 个,第二遍的时候假定第 1 个
  5. // 所以我们要假定第 j 个就行
  6. var minIndex = j
  7. // 因为之前已经把最小的放在最前面了,后面的循环就不需要判断前面的了
  8. // 直接从 j + 1 开始
  9. for (var i = j + 1; i < arr.length; i++) {
  10. if (arr[i] < arr[minIndex]) {
  11. minIndex = i
  12. }
  13. }
  14. // 遍历结束后找到最小的索引
  15. // 第一堂的时候是和第 0 个交换,第二趟的时候是和第 1 个交换
  16. // 我们直接和第 j 个交换就行
  17. var tmp = arr[minIndex]
  18. arr[minIndex] = arr[j]
  19. arr[j] = tmp
  20. }
  1. 一些优化

    • 和之前一样,倒数第二次排序完毕以后,就已经排好了,最后一次没有必要了 ```javascript for (var j = 0; j < arr.length - 1; j++) { var minIndex = j

    for (var i = j + 1; i < arr.length; i++) { if (arr[i] < arr[minIndex]) { minIndex = i } }

    var tmp = arr[minIndex] arr[minIndex] = arr[j] arr[j] = tmp }

    1. - 在交换变量之前,可以判断一下,如果我们遍历后得到的索引和当前的索引一直
    2. - 那么就证明当前这个就是目前最小的,那么就没有必要交换
    3. - 做一我们要判断,最小作引和当前作引不一样的时候,才交换
    4. ```javascript
    5. for (var j = 0; j < arr.length - 1; j++) {
    6. var minIndex = j
    7. for (var i = j + 1; i < arr.length; i++) {
    8. if (arr[i] < arr[minIndex]) {
    9. minIndex = i
    10. }
    11. }
    12. if (minIndex !== j) {
    13. var tmp = arr[minIndex]
    14. arr[minIndex] = arr[j]
    15. arr[j] = tmp
    16. }
    17. }
  2. 至此,选择排序完成

函数参数传递基本数据类型和复杂数据类型的区别

  • 之前我们知道了,基本数据类型和复杂数据类型在存储上是有区别的
  • 那么他们在赋值之间也是有区别的
  • 基本数据类型之间的赋值 ```javascript var num = 10 var num2 = num

num2 = 200

console.log(num) // 100 console.log(num2) // 200

  1. - 相当于是把 num 的值复制了一份一摸一样的给了 num2 变量
  2. - 赋值以后两个在没有关系
  3. - 复杂数据类型之间的赋值
  4. ```javascript
  5. var obj = {
  6. name: 'Jack'
  7. }
  8. var obj2 = obj
  9. obj2.name = 'Rose'
  10. console.log(obj.name) // Rose
  11. console.log(obj2.name) // Rose
  • 因为复杂数据类型,变量存储的是地址,真实内容在 堆空间 内存储
  • 所以赋值的时候相当于把 obj 存储的那个地址复制了一份给到了 obj2 变量
  • 现在 obj 和 obj2 两个变量存储的地址一样,指向一个内存空间
  • 所以使用 obj2 这个变量修改空间内的内容,obj 指向的空间也会跟着改变了

函数的参数

  • 函数的参数也是赋值的之中,在函数调用的时候,实参给行参赋值
  • 和之前变量赋值的规则是一样的
  • 函数传递基本数据类型 ```javascript function fn(n) { n = 200 console.log(n) // 200 }

var num = 100 fn(num) console.log(num) // 100

  1. - 和之前变量赋值的时候一样,在把 num 的值复制了一份一摸一样的给到了函数内部的行参 n
  2. - 两个之间在没有任何关系了
  3. - 函数传递复杂数据类型
  4. ```javascript
  5. function fn(o) {
  6. o.name = 'Rose'
  7. console.log(o.name) // Rose
  8. }
  9. var obj = {
  10. name: 'Jack'
  11. }
  12. fn(obj)
  13. console.log(obj.name) // Rose
  • 和之前变量赋值的时候一样,把 obj 内存储的地址复制了一份一摸一样的给到函数内部的行参 o
  • 函数外部的 obj 和函数内部的行参 o,存储的是