前端三剑客之JavaScript——数组

110 阅读16分钟

1、数据类型分类

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

2、数组含义

字面意思就是数字的组合,准确的来说就是数组是一个数据的集合,也就是我们把一些数据放在一个盒子里面,按照顺序排好。

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

3、创建一个数组

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

3-1、字面量创建一个数组

直接使用[ ]的方式创建一个数组

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

3-2、内置构造行数创建数组

使用 js 的内置构造函数Array创建一个数组

//创建一个空数组 
var arr1 = new Array() 
//创建一个长度为10的数组 
var arr2 = new Array(10) 
//创建一个有内容的数组 
var arr3 = new Array(1,2,3)

3-3、数组的length

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

3-4、数组的索引

  • 索引,也叫做下标,是指一个数据在数组里面排在第几个的位置
  • 注意:在所有的语言里面,索引都是从0开始的
  • 在js里面也一样,数组的索引从0开始
//创建一个数组 
var arr = ['hello','world']
  • 上面这个数组中,第0个数据就是字符串hello,第1个数据就是字符串world
  • 想获取数组中的第几个就使用数组[索引]来获取
var arr = ['hello','world'] 
console.log(arr[0]) //hello 
console.log(arr[1]) //world

4、数组的常用方法

数组是一个复杂数据类型,我们在操作他的时候就不能再想基本数据类型一样的操作了

//创建一个数组 
var arr = [1,2,3] 
//我们想把数组变成只有1和2 
arr = [1,2]

以上的做法是不合理的,因为这样不是在改变之前的数组,相当于弄了一个新的数组给了这个arr变量,是把arr里面存储的地址给换了,也就是把存储空间换了,而不是在之前的空间里面修改,所以我们需要借助一些方法,在不改变存储空间的情况下,把存储空间里面的数据改变了

4-1、push

push是用来在数组的末尾追加元素

如果添加的是一个,就写一个,如果是多个中间用逗号链接

push返回值:是添加了数据进去之后数组的长度

说明:push()方法添加进去内容之后,不会改变原始数据的长度

4-2、pop

pop是用来删除数组末尾的一个元素

pop的返回值:就是被删掉的内容

4-3、unshift

unshift是在数组的前面添加元素

如果添加的是一个,就写一个,如果是多个中间用逗号链接

unshift返回值:是添加了数据进去之后数组的长度

说明:unshift()方法添加进去内容之后,不会改变原始数据的长度

4-4、shift

shift是用来删除数组前面的一个元素

shift的返回值:就是被删掉的内容

4-5、splice

splice是截取数组中的某些内容,按照数组的索引来截取

语法:splice(从哪一个索引位置开始,截取多少个,替换的新元素)(第三个参数可以不写)

  • arr.splice(1,2) 表示从索引1开始截取2个内容
  • 第三个参数没有写,就是没有新内容替换掉截取位置
  • arr.splice(1,2,'我是新内容')表示从索引1开始截取2个内容
  • 然后用第三个参数把截取完空出来的位置填充

4-6、reverse

reverse是用来反转数组使用的

4-7、sort

sort方法默认按照字符的ASCII码进行升序排序

sort是用来给数组排序的(这个只是一个基本的简单用法)

//设置从小到大排列 
sortfunctiona,b){return a - b}) 
//设置从大到小排列 
sortfunctiona, b){return b - a})

4-8、concat

concat是把多个数组进行拼接

和之前的方法有些不一样的地方,就是concat不会改变原始数组,而是返回一个新的数组

4-9、join

join是把数组里面的每一项内容都链接起来,变成一个字符串

可以自己定义每一项之间链接的内容 join(要以什么内容链接)

不会改变原始数组,而是把链接好的字符串返回

4-10、slice

作用:slice能够截取数组,并返回一个新的数组,不改变数组

语法:数组.slice(下标开始值,下标结束值)

  • 注意:从下标开始值开始,保留到下标结束值的前一个结束,如果没有下标结束值(也就是没有第二个参数),就保留到最后一个字符结束。

返回值:返回一个新数组

4-11、indexOf

语法:数组名.indexOf(要查找的数据)

语法二:数组名.indexOf(要查找的数据.索引)

  • 这个语法的意思就是要从指定的索引开始查找该数据
  • 如果有就返回该数据在原数组中第一个出现的位置,如果没有就返回-1

作用:从前往后在数组中查找该数据第一次出现的位置

返回值:如果该数组中有这个数据就返回这个数据第一次出现的位置也就是索引,如果没有返回-1

// indexOf() 方法 
// 语法一: 
var arr = [200, 300, 100, 200, 300, 200, 300] 
var res = arr.indexOf(100) 
console.log('原始数组:', arr); 
console.log('返回值:', res);
// 语法二: 
var arr = [200, 300, 100, 200, 300, 200, 300] 
var res = arr.indexOf(300, 1) 
console.log('原始数组:', arr); 
console.log('返回值:', res);

4-12、lastIndexOf

语法:数组名.lastIndexOf(要查的数据)

语法二:数组名.lastIndexOf(要查的数据.索引)

这个语法的意思是:要从指定的索引开始查找该数据

如果有就返回该数据在原数组中第一个出现的位置,如果没有,就返回-1

作用:从后往前在数组中查找这个数据第一次出现的位置

返回值:如果该数组中有这个数据就返回这个数据第一次出现的位置也就是索引,如果没有返回-1

4-13、forEach

作用:和for循环一个作用,就是用来遍历数组的

语法:arr.forEach(function (item,index,arr){ } )

  • item :表示的是数组内的每一项
  • index:表示的数组内每一项的索引
  • arr:表示的是原始数组

返回值:没有返回值,是undefined

  • forEach()的时候传递的那个函数,会根据数组的长度来执行
  • 数组的长度是多少,这个函数就会执行多少回
var arr = [100, 200, 300, 400, 500] 
    arr.forEach(function(item, index, arr) {
    // 这个函数会根据数组内有多少成员执行多少回 
    console.log('我执行了') 
    console.log(item); 
    console.log(index); 
    console.log(arr); 
    console.log(item, ' ---- ', index, ' ---- ', arr) 
})

4-14、map

和forEach类似,只不过可以对数组中的每一项进行操作,返回一个新的数组

语法:arr.map(function(item,index,arr){ })

返回值:是一个新数组,并且和原始数组的长度一样

  • 新数组内每一个数据都是根据原始数组中每一个数据映射出来的
  • 映射条件以return的形式书写
var arr = [1, 2, 3] 
// 使用 map 遍历数组 
var newArr = arr.map(function(item, index, arr) {
    // item 就是数组中的每一项 
    // index 就是数组的索引 
    // arr 就是原始数组 
    return item + 10 
})
console.log(newArr) // [11, 12, 13]

4-15、filter

作用:和map的使用方式类似,按照我们的条件来筛选数组

语法:arr.filter(function(item,index,arr){ })

返回值:把原始数组中满足条件的筛选出来,组成一个新的数组返回

  • 我们设置的条件就是 > 1
  • 返回的新数组就会是原始数组中所有 > 1的项
var arr = [1, 2, 3] 
// 使用 filter 过滤数组 
var newArr = arr.filter(function(item, index, arr) {
    // item 就是数组中的每一项 
    // index 就是数组的索引 
    // arr 就是原始数组 
    return item > 1
})
console.log(newArr) // [2, 3]

4-16、every

作用:判断数组中是不是每一个数据都满足条件

语法:arr.every(function(item,index,arr){ })

返回值:一个布尔值

  • 如果数组中每一项都满足条件,那么返回值就是true
  • 如果数组中任何一个不满足条件,那么返回的就是false

判断条件以return书写

var arr = [100, 200, 300, 400, 500] console.log('原始数组 : ', arr) var res = arr.every(function(item, index, srr) { console.log(item) console.log(index); // 以 return 的形式书写 判断 条件 return item < 500 // return index > 6 }) console.log('返回值 : ', res) //false

4-17、some

作用:判断数组中是不是有某一个满足条件

语法:arr.some(function(item,index,arr){ })

返回值:一个布尔值

  • 如果数组中有任何一个满足条件,那么返回值就是true
  • 如果数组中所有的都不满足条件,那么返回值就是false

var arr = [100, 200, 300, 400, 500] console.log(arr) var res = arr.some(function(item, index, arr) { console.log(item); console.log(index); // 以 return 的形式书写 判断 条件 return item < 50 // return index > 6 }) console.log(res) //false

4-18、reduce

作用:进行叠加累计,函数根据数组中的成员进行重复调用

语法:arr.reduce(function(prev,item,index,arr){},初始值)

  • prev:初始值或每一次叠加后的结果
  • item:每一项
  • index:索引
  • arr:原始数组
  • 初始值:默认是数组索引 0 位置数据,表示从什么位置开始叠加

返回值:返回最终的结果

4-19、find

作用:查找数组中某一个数据

语法:arr.find(function(item,index,arr){})

返回值:数组中你查找的该数据,返回的只有第一个满足的数据

查找条件以return的形式书写

var arr = [100, 200, 301, 400, 500] 
console.log(arr) 
// 我想找到原始数组中的哪一个 奇数 
var res = arr.find(function(item, index, arr) { 
    console.log(item);
    console.log(index); 
    // 以 return 的形式书写查找条件
    return item % 2 === 1 
})
console.log(res)

4-20、findIndex

作用:查找数组中某一个数据

语法:arr.findIndex(function(item,index,arr){ })

返回值:数组中你查找到的该数据所在的索引位置

查找条件以return的形式书写

var arr = [100, 200, 301, 400, 500] 
console.log(arr) 
// 我想找到原始数组中的哪一个 奇数 
var res = arr.find(function(item, index, arr) { 
    console.log(item);
    console.log(index); 
    // 以 return 的形式书写查找条件
    return item % 2 === 1 
})
console.log(res)

5、如何循环遍历一个数组

for和for in循环

  • 因为数组的索引就可以获取数组中的内容
  • 数组的索引又是按照0-n顺序循环的
  • 我们就可以使用for循环来循环数组,因为for循环我们也可以设置成0-n顺序添加
  • 我们把这个行为叫做遍历
var arr = [1,2,3,4,5] 
//使用for循环遍历数组 
for(var i = 0;i < arr.length;i++){
    console.log(arr[i]) 
} 
//会在控制台打印1,2,3,4,5
  • i < arr.length因为length就是数组的长度,就是一个数字,我们可以直接用它来决定循环次数
  • console.log(arr[i])因为随着循环,i的值会从0开始依次增加
  • 所以我们实际上是在打印arr[0]、arr([1])、……
var obj = { name:"gege", age:18 } 
for(var key in obj){
    console.log(key) 
} 
//会在控制台打印两次内容,分别是name和age
  • for in循环的遍历是按照对象中有多少成员来决定的
  • 有多少成员就执行多少次
  • key是我们自己定义的变量,就和for循环的时候我们定义的i是一个道理
  • 在每次循环的过程中,key就代表着对象中某一个成员的属性名

6、数组的排序

  • 排序就是把一个乱序的数组,通过处理之后,让他变成一个有序的排序
  • 常见的两种数组排序方法冒泡排序和选择排序

6-1、冒泡排序

  • 先遍历数组,让挨着的两个进行比较,如果前一个比后一个大,那么就把两个换个位置
  • 数组遍历一遍之后,那么最后一个数字就是最大的那个了
  • 然后进行第二遍的遍历,还是按照之前的规则,第二大的数字就会跑到倒数第二的位置
  • 依次类推,最后就会按照顺序把数组排好了

分步走:

1、我们先准备一个乱序的数组

var arr = [3, 1, 5, 6, 4, 9, 7, 2, 8];

2、先不着急循环,先来看数组里面内容换个位置

// 假定我现在要让数组中的第 0 项和第 1 项换个位置 
// 需要借助第三个变量
    var tmp = arr[0] 
    arr[0] = arr[1] 
    arr[1] = tmp

3、第一次遍历数组,把最大的放到最后面去

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]

第一次结束之后,数组的最后一个,就会是最大的那个数字

然后我们把上面这段代码执行多次,数组有多少项就执行多少次

4、按照数组的长度来遍历多少次

for(var j = 0;j < arr.length;j++){ 
    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; 
    } 
  }
} 
//结束以后,数组就排序好了

5、优化

假设数组的长度是9,第一次排完的时候,已经把最大的数字放在了最后面,那么第二次的时候,已经不需要再次比较最后两个了,以此类推,那么其实每次遍历的时候,就遍历当前次数-1;而且每次排序的时候,最后一个也肯定是固定了,再次遍历就没用了,所以说遍历的次数也可以减1。

for (var j = 0; j < arr.length - 1; j++) {
    for (var i = 0; i < arr.length - 1 - j; i++) { 
        // 判断,如果数组中的当前一个比后一个大,那么两个交换一下位置 
        if (arr[i] > arr[i + 1]) { 
        var tmp = arr[i]
        arr[i] = arr[i + 1] 
        arr[i + 1] = tmp 
        } 
    }
}

6、至此,一个冒泡排序就完成了

6-2、选择排序

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

1、准备一个乱序的数组

var arr = [3, 1, 5, 6, 4, 9, 7, 2, 8]

2、假定数组中的第0个是最小数字的索引

var minIndex = 0;

3、遍历数组,判断,只要数字比我小,那么就替换原先记录的索引

var minIndex = 0; 
for(var i = 0;i < arr.length;i++){ 
    if(arr[i]<arr[minIdex]){
    minIndex = i; 
    } 
} 
//遍历结束后找到最小的那个索引
//让第minIndex个和第0个交换 
var tmp = arr[arrIndex] 
arr[arrIndex] = arr[0] 
arr[0] = tmp

4、按照数组的长度重复执行上面的代码

for(var j = 0; j<arr.length;j++){
    //因为第一遍的时候假定第0个,第二遍的时候假定第1个 
    //所以我们要假定第j个就行 
    var minIndex = j; 
    for(var i = j + 1;i < arr.length;i++){
        if(arr[i] < arr[minIndex]){ 
        minIndex = i; 
    }
}
//遍历结束后找到最小的索引 
//第一趟的时候是和第0个交换,第二趟的时候是和第1个交换 //我们直接和第j个交换就行 var tmp = arr[minIndex] 
arr[minIndex] = arr[j] 
arr[j] = tmp 
}

5、一些优化

  • 和之前一样,倒数第二次排序完毕以后,就已经排序好了,最好一次没有必要了
  • 在交换变量的之前,可以判断一下,如果我们遍历后得到的索引和当前的索引一样的,那么就证明当前这个是最小的,没有必要交换,如果不一样,才交换
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 
    }
} 
if (minIndex !== j) {
    var tmp = arr[minIndex] 
    arr[minIndex] = arr[j] 
    arr[j] = tmp 
    } 
}

6、选择排序完成

7、数组塌陷

含义

当数组执行删除单元操作时,被删除单元,之后的单元,会前移,进而顶替被删除单元,出现在被删除单元的位置上,造成数组长度减少的情况,这样的现象称为数组的坍塌

8、函数参数传递基本数据类型和复杂数据类型的区别 ( 了解 )

基本数据类型和复杂数据类型在存储上是有区别的,他们在赋值的之间也是有区别的

基本数据类型之间的赋值

var num = 10 
var num2 = num 
num2 = 200 
console.log(num) // 100 
console.log(num2) // 200
  • 相当于是把num的值复制一份一模一样的给了num2变量
  • 赋值以后两个没有关系

复杂数据类型之间的赋值

var obj = { name: 'Jack' } 
var obj2 = obj 
obj2.name = 'Rose' 
console.log(obj.name) // Rose 
console.log(obj2.name) // Rose
  • 因为复杂数据类型变量存储的是地址,真实内容在堆空间内存储
  • 所以赋值的时候相当于把obj存储的那个地址复制了一份给到了obj2变量
  • 现在obj和obj2两个变量存储的地址是一样的,指向一个内存空间
  • 所以使用obj2这个变量修改空间内的内容,obj指向的空间也会跟着改变了

函数的参数

  • 函数的参数也是赋值的之中,在函数调用的时候,实参给行参赋值
  • 和之前变量赋值的规则是一样的

函数传递基本数据类型

function fn(n) { 
    n = 200 
    console.log(n) // 200 
} 
var num = 100 
fn(num) 
console.log(num) // 100
  • 和之前变量赋值的时候一样,在把 num 的值复制了一份一摸一样的给到了函数内部的行参 n
  • 两个之间在没有任何关系了

函数传递复杂数据 类型

function fn(o) { 
    o.name = 'Rose' 
    console.log(o.name) // Rose 
} 
var obj = { name: 'Jack' } 
fn(obj) console.log(obj.name) // Rose
  • 和之前变量赋值的时候一样,把 obj 内存储的地址复制了一份一摸一样的给到函数内部的行参 o
  • 函数外部的 obj 和函数内部的行参 o,存储的是一个地址,指向的是一个存储空间
  • 所以两个变量操作的是一个存储空间
  • 在函数内部改变了空间内的数据
  • obj 看到的也是改变以后的内容