数组
就是用来存储数据,可以存储多个数据,数组是一个有序的数据集合
创造数组的方式
1.字面量方式创造
-
创造了一个空数组: var 变量名 = []
-
创造一个带有数据的数据:var 变量名 = [数据1,数据2,数据3。。。。]
-
注意:数组中可以存储任意类型的数据,但是我们一般建议存好存相同类型的数据
// 1. 创造了一个空数组,变量名字叫做arr
var arr = []
console.log(arr);
// 2.创造了一个带有数据的数组,数据分别是:100 200 300 hello,总共个4条数据
var arr2 = [100, 200, 300, 'hello', '你好']
console.log(arr2);
2.内置构造函数方式创造
-
创造一个空数组:var 变量名 = new Array()
-
创造带有数据的:var 变量名 = new Array(数据1,数据2,。。。。)
-
特殊情况:如果()中只写一个数据,并且这个数据是一个数字,那么此时这个数字就是数组的长度了,数据都是空的,用empty表示
-
// 创造一个空数组 var arr3 = new Array() console.log(arr3); // 创造带有数据的 var arr4 = new Array(100, 200, 300, 'hello') console.log(arr4); // 此时的100指的是数组的长度 var arr5 = new Array(100) console.log(arr5);
数组的索引(下标)
- 数组中的每个数据都有自己对应的下标
- 下标是自带的
- 下标:在数组中数据从左到右从0开始依次+1,也就是第一个数据的索引是0,依次+1
数组的基本操作
1.操作数组的length属性
-
length:这个单词是长度的意思,代表数组的长度,也就是数组中数据的个数
-
关于length属性他是一个读写属性
(1)读:可以获取到length的值
语法:变量名.length
(2)写:可以设置length的值
语法:变量名.length = 值
-
当设置的比原来的长度小:就拥有删除的意思,从数组的末尾删除到符合的个数为止
-
当设置的比原来的长度大:多出来的位置用empty表示
-
当设置的和原来的长度一致:相当于没设置。
2.操作数组的索引
-
索引也是可读可写的,可以通过索引获取到某一个数据,也可以去设置某一个索引对应的数据
-
读:获取 语法:变量名[索引]
(1)如果该索引存在会得到该索引对应的数据
(2)如果该索引不存在结果是undefined
- 写:设置数据 语法:变量名[索引] = 值
(1)如果该索引存在就是修改该索引对应的数据
(2)如果索引不存在:
①当你写的索引值刚好和数组的长度一致:就是在数组的末尾添加一条数据
②当你写的索引值比数组的长度大:中间位置的数据用empty表示
3.遍历数组
-
从头到尾挨个访问一遍数组中的数据
-
遍历需要借助于循环即可,因为获取数组中的数据核心关键点需要借助于数组的索引
-
索引刚好是一组有过i率的数字,从0开始依次+1
-
刚好循环可以创造一组由规律的数组
-
循环的起始值:0开始
-
循环的结束值:<=数组的长度-1 或者 <数组的长度
-
步长:+1
-
var arr1 = [100, 200, 300, 400, 500] for (var i = 0; i < arr1.length; i++) { // i指的就是数组的索引 console.log(arr1[i]);//arr[4] }
数组中的常见方法
1.push()方法
- 语法:数组名.push(数据)
- 意思:向数组的末尾追加一条数据
- 返回值:追加了数据之后数组的长度
2.pop()方法
- 语法:数组名.pop()
- 意思:删除数组末尾的一条数据
- 返回值:你删除的那条数据
3.unshift()
- 语法:数组名.unshift(你要加的数据)
- 意思:从数组的开头添加一条数据
- 返回值:数组的长度
4.shift()
- 语法:数组名.shift()
- 意思:从头删除一条数据
- 返回值:被删除的那个数据
5.reverse()
- 语法:数组名.reverse()
- 意思:反转数组,将数组中的数据逆序
- 返回值:反转之后的数组
6.sort()方法
-
语法1:数组名.sort()
意思:对数组中的数据进行排序(从小到大)
排序规则:一位一位数字阅读,比较。
-
语法2:数组名.sort(function(a,b){return a-b})
记住:a-b按照从小到大
记住:b-a按照从大到小
7.splice()
-
语法1:数组名.splice(开始索引,个数)
意思:从数组中截取出一部分数据
返回值:你截取出来的数据,是一个新数组
注意:如果不写个数,那么就是从开始位置一直截取到最后
-
语法2:数组名.splice(开始索引,个数,你要插入的新数据1,数据2,数据3,。。。。)
-
记住:从哪里开始截取,就从哪里开始插入
以上这几个方法的共同点:都是直接改变原始数组
8.concat()
- 语法:数组名.concat(你要拼接的数据1,数据2。。。)
- 将数据拼接成一个新的数组。参与拼接的数据可以是具体的数值也可以是另外一个数组
- 返回值:拼接好之后的新数组。
9.join()
- 语法:数组名.join(连接符)
- 作用:用连接符将数组中的数据连接成一个字符串
- 返回值:连接好的字符串
- 注意:不写连接符,默认是逗号连接
10.slice()
-
语法:数组名.slice(开始位置,结束位置)
-
注意:
(1)不包含结束位置
(2)如果不写结束位置,会一直截取最后
(3) 如果开始和结束位置都不写,就是从头到尾全部截取,相当于进行了一次复制操作
(4)位置也可以写负数,数组中的索引用负数表示的时候,需要从右到左看,最后一个数据是-1,
11.indexOf()
-
语法:数组名.indexOf(数据)
作用:根据数据查找到该数据‘第一次’对应的索引。如果该数据不存在。那么就是-1
用这个方法可以验证一个数据到底在不在数组中,如果不再结果一定是-1
-
语法2:数组名.indexOf(数据,开始位置)
作用:从开始位置起找该数据第一次出现的索引
注意:包含开始位置
12.lastIndexOf()
写法同上
区别:indexOf是从左到右找,lastIndexOf是从右到左找
以上这几个方法的共同点:不改变原始数组
数组的常用方法
1.forEach()
-
语法:数组名.forEach(function(item,index,origin){})
item:表示数组中的每一个数据
index:表示数组的索引
origin:表示原数组(会根据数组的长度执行)
注意:函数中的起名是可以随意起名的,且这三个函数不是必须需要的
-
作用:遍历数组
-
var arr = [100, 200, 300, 400, 500] var sum = 0 arr.forEach(function(item){ // item指的就是数组中每一个数据 sum+=item }) console.log(sum); //1500
2.map()
-
语法:数组名.map(function(item,index,origin){})
-
作用:可以对数组进行加工处理,将加工处理的新结果映射出一份新数组
-
返回值:加工处理的新数组
-
注意:加工的语句需要用return的形式书写
-
var arr = [100, 200, 300, 400] var res = arr.map(function (item) { // item指的就是arr中的每一个数组 return item += item * 0.3 }) console.log(arr); //[100,200,300,400] console.log(res); //[130,260,390,520]
3.filter()
-
语法:数组名.filter(function(item,index,origin){})
-
作用:对数组中的数据进行过滤,筛选出符合条件的数据,并加入新数组
-
返回值:过滤好的新数组
-
注意: 过滤条件用return形式书写.
-
var arr = [1, 2, 3, 4, 5, 6] var res = arr.filter(function (item) { return item % 2 == 0 }) console.log(arr);//[1, 2, 3, 4, 5, 6] console.log(res);//[1,3,5]
4.find()
-
语法:数组名.find(function(item,index,origin){})
-
作用:从原始数组中找符合条件的’第一项’数据
-
返回值:符合条件的第一个数据,如果没有符合条件的就undefined
-
注意: 查找条件写在return后面.
-
var arr = [1, 2, 3, 4, 5, 6] var res = arr.find(function (item) { return item % 2 == 0 }) console.log(res);//2
5.findIndexOf()
-
与find()用法一样
-
区别:find是找数据,findIndex是找符合条件的数据的索引,找到符合条件的:就返回索引,找不见就是-1
-
var arr = [1, 2, 3, 4, 5, 6] var res = arr.findIndex(function (item) { return item > 3 //3 return item % 2 == 0//1 return item > 6//-1 }) console.log(res);
6.every
-
语法:数组名.every(function(item,index,origin){})
-
作用:判断数组内的数据是否每一个都是满足条件的
-
返回值:一定是一个布尔类型,每一个都满足就是true,只要有一个不满足是false (和&&的意思一样)
-
var arr = [1, 2, 3, 4, 5, 6] var res = arr.every(function (item) { return item <= 6 }) console.log(res); //true
7.some()
-
语法:数组名.some(function(item,index,origin){})
-
作用:判断数组中是否有满足条件的
-
返回值:只要有一个满足条件,结果就是true,所有都不满足,结果才是false(类似于||的意思)
-
var arr = [1, 2, 3, 4, 5, 6] var res = arr.some(function (item) { return item < 0 }) console.log(res); //true
8.reduce
-
语法:数组名.reduce(function(){},init)
-
作用:将数组中所有数据进行累加的
-
返回值:累加之后的结果
-
reduce中传递2个参数
第一个是匿名函数,函数函数参数的写法:可以写4个参数
第一个参数用来表示初始值,或者上一次的运算结果,prev
第二个参数用来表示数组中的每一个数据,item
第三个参数用来表示索引,index
第四个参数用来表示原始数组,origin
第二个是初始值,初始值可写可不写.
-
var arr = [1, 2, 3, 4, 5, 6] var res = arr.reduce(function (prev, item) { console.log("prev:"+prev+'item:'+item); return prev + item }) console.log(res);// prev:1item:2 // prev:3item:3 // prev:6item:4 // prev:10item:5 // prev:15item:6 // 21
冒泡排序
冒泡排序是排序思想。
思想的核心:让相邻的2个数据进行比较,如果要进行从小到大的排序,把大的元素往后放。
-
先遍历数组,让挨着的两个进行比较,如果前一个比后一个大,那么就把两个换个位置
-
数组遍历一遍以后,那么最后一个数字就是最大的那个了
-
然后进行第二遍的遍历,还是按照之前的规则,第二大的数字就会跑到倒数第二的位置
-
以此类推,最后就会按照顺序把数组排好了
-
我们先来准备一个乱序的数组
var arr = [3, 1, 5, 6, 4, 9, 7, 2, 8]
- 接下来我们就会用代码让数组排序
-
先不着急循环,先来看数组里面内容换个位置
// 假定我现在要让数组中的第 0 项和第 1 项换个位置 // 需要借助第三个变量 var tmp = arr[0] arr[0] = arr[1] arr[1] = tmp
-
第一次遍历数组,把最大的放到最后面去
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]
- 第一次结束以后,数组中的最后一个,就会是最大的那个数字
- 然后我们把上面的这段代码执行多次。数组有多少项就执行多少次
-
按照数组的长度来遍历多少次
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 } } } // 结束以后,数组就排序好了
-
给一些优化
-
想象一个问题,假设数组长度是 9,第八次排完以后
-
后面八个数字已经按照顺序排列好了,剩下的那个最小的一定是在最前面
-
那么第九次就已经没有意义了,因为最小的已经在最前面了,不会再有任何换位置出现了
-
那么我们第九次遍历就不需要了,所以我们可以减少一次
for (var j = 0; j < arr.length - 1; 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 } } }
-
第二个问题,第一次的时候,已经把最大的数字放在最后面了
-
那么第二次的时候,其实倒数第二个和最后一个就不用比了
-
因为我们就是要把倒数第二大的放在倒数第二的位置,即使比较了,也不会换位置
-
第三次就要倒数第三个数字就不用再和后两个比较了
-
以此类推,那么其实每次遍历的时候,就遍历
当前次数 - 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 } } }
-
-
至此,一个冒泡排序就完成了
-
选择排序
-
先假定数组中的第 0 个就是最小的数字的索引
-
然后遍历数组,只要有一个数字比我小,那么就替换之前记录的索引
-
知道数组遍历结束后,就能找到最小的那个索引,然后让最小的索引换到第 0 个的位置
-
再来第二趟遍历,假定第 1 个是最小的数字的索引
-
在遍历一次数组,找到比我小的那个数字的索引
-
遍历结束后换个位置
-
依次类推,也可以把数组排序好
-
准备一个数组
var arr = [3, 1, 5, 6, 4, 9, 7, 2, 8]
-
假定数组中的第 0 个是最小数字的索引
var minIndex = 0
-
遍历数组,判断,只要数字比我小,那么就替换掉原先记录的索引
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
-
按照数组的长度重复执行上面的代码
for (var j = 0; j < arr.length; j++) { // 因为第一遍的时候假定第 0 个,第二遍的时候假定第 1 个 // 所以我们要假定第 j 个就行 var minIndex = j // 因为之前已经把最小的放在最前面了,后面的循环就不需要判断前面的了 // 直接从 j + 1 开始 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 }
-
一些优化
-
和之前一样,倒数第二次排序完毕以后,就已经排好了,最后一次没有必要了
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 }
-
在交换变量之前,可以判断一下,如果我们遍历后得到的索引和当前的索引一直
-
那么就证明当前这个就是目前最小的,那么就没有必要交换
-
做一我们要判断,最小作引和当前作引不一样的时候,才交换
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 } }
-
-
至此,选择排序完成
-
数组的塌陷
数组坍陷的原因
从数组中删除一个数据之后,从删除数据之后的所有数据的索引会向前递进
var arr = [100, 200, 300, 400, 500, 600]
//利用splice方法挨个删除数组中所有的数据,splice一次只能删除1个,从100开始删除.把数组数据删除干净[]
//(1) i = 0 执行arr.splice(0,1),删除之后数组的样子:
[200,300,400,500,600]
0 1 2 3 4
//(2) i = 1, 执行arr.splice(0,1),删除之后数组的样子:
[300,400,500,600]
0 1 2 3
//(3)i = 2,执行arr.splice(0,1),删除之后数组的样子:
[400,500,600]
0 1 2
//(4)i = 3,执行arr.splice(0,1),删除之后数组的样子:
//此时i=3时 i<arr.length即就是i<3不成立 所以循环不会执行
var arr = [100, 200, 300, 400, 500, 600]
// 0 1 2 3 4 5
for(var i = 0;i<arr.length;i++){
i = 3 3<3;i++
arr.splice(0,1)
}
console.log(arr); //[400,500,600]
解决数组塌陷的办法
出现塌陷:保证步长不发生改变,原地不动即可, 下一步操作如果要++保持元素不动就是在++之前–即可
var arr = [100, 200, 300, 400, 500, 600]
/*
(1)i = 0;i<6,执行 arr.splice(0, 1)
[200,300,400,500,600]
0 1 2 3 4
i--//-1
i++//0
(2)i = 0;i<5;执行 arr.splice(0, 1)
[300,400,500,600]
0 1 2 3
i--
i++
(3)i = 0;i<4;执行 arr.splice(0, 1)
[400,500,600]
0 1 2
i--
i++
(4)i=0;i<3;执行 arr.splice(0, 1)
[500,600]
0 1
i--
i++
(5)i=0;i<2;执行 arr.splice(0, 1)
[600]
i--
i++
(6)i=0;i<1;执行 arr.splice(0, 1)
[]
i--
i++
(7)i=0;i<0
*/
for (var i = 0; i < arr.length; i++) {
arr.splice(i, 1)
i--
}
console.log(arr);
数组的去重
方法一
思路:
-
先遍历得到数组中每一个数据
-
拿到每一个数据之后,让每一个数据都和他身后所有的数据进行检测,如果他身后的所有数据中出现了相同的,就代表重复,需要删除
-
利用indexOf():数组名.indexOf(数据,开始位置) 作用:从开始位置起找该数据第一次出现的索引
-
var arr = [1, 2, 2, 2, 3, 3, 3, 2] for (var i = 0; i < arr.length; i++) { var res = arr.indexOf(arr[i], i + 1)//res中存储的就是后面重复出现数据的索引 // 只要res的结果不为-1代表后面有一样的数据,需要删除后面的这个数据 if (res != -1) { arr.splice(res, 1) i-- } } console.log(arr);
方法二
借助于新数组
思路:
-
创造一个空数组,遍历原始数组,拿到每一个数据
-
将原始数组中的数据挨个push到新数组中,但是在push之前需要检测该数据在不在新数组中,如果不在才能执行push
-
var arr = [1, 2, 2, 2, 3, 3, 3, 2] var newArr = [] for (var i = 0; i < arr.length; i++) { // arr[i]就代表原始数组中的每一个数据 // 检测arr[i]在不在新数组中 var res = newArr.indexOf(arr[i]) // res的结果只要是-1就代表新数组中没有出现过该数据,才能加入 if (res === -1) { newArr.push(arr[i]) } } console.log(newArr);
Math中的常用方法
1.Math.random()
生成随机数,取值之间在0-1之间,取不到最大值.
2.Math.round(数字)
四舍五入取整
3.Math.ceil(数字)
向上取整
4.Math.floor(数字)
向下取整
5.Math.abs(数字)
绝对值
6.Math.pow(x,y)方法
求x的y次方,等价于**
7.Math.sqrt(数字):
求算数平方根
8.Math.max(数字1,数字2,…)
求一堆数字中的最大值
9.Math.min(数字1,数字2,…)
求一堆数字中的最小值
10.Math.PI
圆周率
求随机数
Math.round(Math.random() * (max-min)+min)
// 得到0-1之间的随机数
var res = Math.random()
console.log(res);
// 如何得到0-10之间的随机数
var res = Math.random() * 10
console.log(res);
// 得到0-10之间的随机整数
var res = Math.round(Math.random() * 10)
console.log(res);
// 得到3-7之间的随机整数
var res = Math.round(Math.random() * 4 + 3)//0-4 3-7
console.log(res);
// 求10-20的随机整数
var res = Math.round(Math.random() * 10 + 10)//10-20
扩展的小方法
1.toString()
-
将十进制转成其他进制的方法
-
语法:十进制的数字.toString(你要转成几进制)
-
var num = 11 // 我想把这个5,也就是num转成二进制 var res = num.toString(16) console.log(res);//b
2.parseInt()
-
将其他进制转成十进制
-
语法:parseInt(数字,你要把这个数字当作几进制)
-
var res = parseInt(10, 2) console.log(res);//2
3.toFixed()
-
语法:数字.toFixed(你要保留几位)
-
保留小数点的时候会自动进行四舍五入
-
var num = 3.141634567 var res = num.toFixed(3) console.log(res);//3.142
函数参数传递基本数据类型和复杂数据类型的区别
-
之前我们知道了,基本数据类型和复杂数据类型在存储上是有区别的
-
那么他们在赋值之间也是有区别的
-
基本数据类型之间的赋值
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
指向的空间也会跟着改变了
总结
- 数组会存储在内存上,内存上我们针对于不同的数据类型存储的方式是不一样。
- 在内存中:我们可以再细分为:栈内存和堆内存
- 基本(简单)数据类型:是存储在栈内存上面的
- 引用(复杂)数据类型:是存储在堆内存上面的
- 变量是存储栈中,变量的数据如果是基本类型,该数据也是再栈中,如果变量的数据是引用类型,该数据会存储到堆当中