数组和循环
数组入门和循环
一 数组入门
数组用于存储一组相关数据。作用和对象类似。
数组是有序的数据结构。
对象是无序的数据结构。
1.1:数组的相关概念
数组的创建,分两种方式:
1:直接量
2:构造函数
// 直接量
let arr = [1,2,3];
// 构造函数
let arr = new Array(1,2,3);
数组内的每个数据叫做数组的元素。或者叫做数组的数据项,每一项。(和html的元素不是一个意思)
可以通过元素的下标访问数组元素。(下标相当于门牌号)(对象通过属性名访问属性值)
数组的元素下标默认从0开始。
数组的长度(元素个数)可以通过length获取。
如果访问一个不存在的元素,得到undefined。(访问不存在的对象属性也是undefined)
// '班长','学委','体委'是数组的元素,对应的下标是0,1,2
let arr = ['班长','学委','体委'];
// 访问第一个元素
console.log(arr[0]);
// 访问第二个元素
console.log(arr[1]);
// 访问最后一个元素
console.log(arr[arr.length-1])
// 访问第101个元素,不存在,得到undefined
console.log(arr[100])
// 访问数组的长度。
console.log(arr.length)
1.2:数组的增删改查
1.2.1: 增加元素
可以通过没被占用的下标添加新元素
let arr=[1,2,3];
// 下标3没被占用,为数组添加了第四个元素4
arr[3] = 4;
// 如果添加第6个元素,则第5个元素是空的。
arr[5] = 6;
console.log(arr[4]);//undefined
1.2.2:删除元素
可以通过length=0来删除所有元素。删除指定元素后期学。
// 删除所有元素
let arr=[1,2,3];
arr.length = 0;
1.2.3:修改元素
通过已经被占用的下标修改元素
// 把第一个元素从1修改为100
let arr=[1,2,3];
arr[0] = 100;
1.2.4:查找元素
通过下标查找元素,如果元素不存在,得到undefined
下标从0开始,依次增加1.
let arr=[1,2,3];
console.log(arr[0]);//1
console.log(arr[10]);//undefined
1.3:数组常见格式
数组内元素的数据类型一般是,number,string,array和object
// 很简单的数组,元素类型分别是number和string
let arr = [1,2,3];
let arr = ['你','我','它'];
// 元素数据类型不一致也可以
let arr = [1,'你',true]
1.3.1:多维数组
数组的元素又是数组,称之为多维数组,常见二维数组,三维数组。
// 二维数组,arr的元素都是数组,分别是[1,2]和[2,4];
let arr = [[1,2],[3,4]];
// 打印arr的第一个元素.
console.log(arr[0]);//[1,2]
// 打印arr的第一个元素的第一个元素.
console.log(arr[0][0]);//1
1.3.2:对象数组
数组的元素是对象,称为对象数组。
// 数组的元素是对象,分别是{name:'幂幂'}和{name:'超越'}
let arr = [{name:'幂幂'},{name:'超越'}];
// 访问数组第一个元素.
console.log(arr[0]);//{name:'幂幂'}
// 访问数组第一个元素的name属性.
console.log(arr[0].name);//幂幂
二 获取元素进阶
获取元素可以通过id获取到一个元素,如果有10个元素,获取10次肯定是很麻烦的。
可以通过以下方法一次性获取多个元素,这时获取到的不是html标签,而是装着html标签的数组!
2.1:在页面中查找所有符合条件的标签
以下方法在document内查找所有符合条件的标签。
// 获取页面中所有的div元素, aDiv是数组!
let aDiv = document.getElementsByTagName('div');
// 获取页面中所有类名为active的元素,aDiv是数组!
let aDiv = document.getElementsByClassName('active');
// 获取页面中选择器为div.active的所有元素,aDiv是数组!
let aDiv = document.querySelectorAll('div.active');
通过以上方法获取到的是数组,可以通过数组下标来操作html标签:
// 通过标签名获取元素, aDiv是数组!
let aDiv = document.getElementsByTagName(元素标签名);
// 通过数组下标来设置第一个div的背景色
aDiv[0].style.background = 'red'
不管元素有多少个,通过以上方法获取的永远是一个数组,不是html标签!
通过以上方法获取元素,一定记得加下标!
// 通过标签名获取body。
let aBody = document.getElementsByTagName('body');
// 错,aBody是数组,不是标签
aBody.style.background = 'red';
// 正确,只能通过数组aBody的下标来获取body标签。
aBody[0].style.background = 'red';
2.2:在指定元素内查找所有符合条件的标签。
以下方法在指定的#wrap内获取符合条件的所有标签。
let oWrap = document.getElementById('wrap');
// 获取oWrap中所有的div子孙元素
let aDiv = oWrap.getElementsByTagName('div');
// 获取oWrap中所有类名为active的子孙元素
let aDiv = oWrap.getElementsByClassName('active');
// 获取oWrap中所有选择器为div.active的子孙元素
let aDiv = oWrap.querySelectorAll('div.active');
// 获取oWrap的所有子元素。(不获取孙子元素,不区分标签)
let aDiv = oWrap.children
难点:
querySelectorAll和getElementsByTagName以及getElementsByClassName的区别:
querySelectorAll是静态获取元素,一旦获取,length不会随着标签的增删而发生变化。
getElementsByTagName以及getElementsByClassName是动态获取,length会随着元素增删而变化。
PS:利用JS数组获取页面元素,只是一种映射,无法通过删除JS数组中的元素来实现在页面上删除标签
三 控制结构--循环
js 有两种控制结构,循环和判断。
循环用于处理逻辑相同的 js 操作。便于书写和批量处理。
// 相同的操作,如果需要执行多次,只能书写多次,这样很麻烦,维护也麻烦
console.log(100);
console.log(100);
console.log(100);
console.log(100);
console.log(100);
// 书写一个执行5次的循环,执行相同的操作。这样更简单
for(let i=0;i<5;i++){
console.log(100);
}
语法:
// 当表达式2返回值为false,则循环终止
for(表达式1;表达式2;表达式3){
循环体代码
}
表达式2永远不为false,则循环永远无法停止,这种循环称之为死循环。
难点:
1:怎么写。
写循环,其实就是在教浏览器数数。i 就是计数变量。至于从几开始数,怎么数,数到几,都可以设置。
let i = 0;表示从0开始数,i<5表示数到5就停,i++,表示每次数数加1。
自然可以从任何数开始数,数到任何数就停,每次数数可以加任何数减任何数。
// 从-1开始数,数数不超过4,每次数数+2
for(let i=-1;i<=4;i+=2){
循环体代码
}
2:循环执行顺序
循环执行顺序:
表达式1>表达式2判断>循环体代码>表达式3>表达式2判断.......直到表达式2返回false,则终止循环.
//顺序:
//1:let i = 0;
//2:i<5,判断i<5的返回值是否为true,如果是,执行第3步,否则终止循环
//3:console.log(100);执行循环代码体;
//4:i++,i的值+1
//5:i<5,判断i<5的返回值是否为true,如果是,执行第6步,否则终止循环
//..............直到i<5返回false.
for(let i=0;i<5;i++){
console.log(100);
}
知道了顺序,就可以看懂任何循环代码.
3:如何看懂循环在做什么
看懂代码,需要注意两件事情:
1:循环多少次。
2:循环体代码是什么。
// 1:这个循环循环3次
// 2:循环体代码是判断
// if(true){
// console.log(1000)
// }
for(let i=0;i<3;i++){
if(true){
console.log(1000)
}
}
// 因此以上循环代码的意思是:
// 执行3次判断
// if(true){
// console.log(1000)
// }
// -------------------------------------------------------------------------
// 1: 这个循环循环5次
// 2:循环体代码是添加事件oBtn.onclick = function(){console.log(10000)}
for(let i=0;i<=4;i++){
oBtn.onclick = function(){console.log(10000)}
}
// 因此以上循环代码的意思是:
// 执行5次添加事件。即执行三次oBtn.onclick = function(){console.log(10000)}
// --------------------------------------------------------------------------
// 1:这个循环循环5次
// 2:循环代码体又是一个循环
// for(let j=0;j<5;j++){
// console.log(100);
// }
for(let i=0;i<=4;i++){
for(let j=0;j<5;j++){
console.log(100);
}
}
// 因此以上循环代码的意思是:
// 执行5次内部循环
// for(let j=0;j<5;j++){
// console.log(100);
// }
// 内部循环的意思的分析方法同上.
4:循环中循环计数 i 的值
循环的过程中 i 的值一直在变。
// 以下循环除了执行了5次console.log(100)之外,还执行了5次 i++,意即i = i+1
for(let i=0;i<5;i++){
console.log(100);
}
// 以上循环可以改写成
for(let i=0;i<5;){
console.log(100);
i = i + 1;
}
// 这样写,i = i+1就成了循环体的一部分。意即i的值每次循环都会改变。
// 这个循环执行了5次,每次循环对应 i 的值,依次为0,1,2,3,4
利用每次 i 的值,可以实现批量处理数据。
// 利用每次循环中i的值作为数组的下标,遍历数组中的每一个元素。
let arr = [1,2,3,4,5];
for(let i=0;i<arr.length;i++){
console.log(arr[i])
}
// 利用每次循环中i的值作为数组的下标,遍历aDiv中的每一个html标签。
// 以下例子是给aDiv内的每一个div都添加一个事件
let aDiv = document.getElementsByTagName('div');
for(let i=0;i<arr.length;i++){
console.log(aDiv[i]);
aDiv[i].onclick = function(){console.log(10000)}
}
注意:
js 代码是在html的解析阶段执行的,循环也是在html的解析阶段执行完成的。
因此,页面渲染结束,循环一定执行完毕了,循环执行完毕后,循环中 i 的值肯定是最后一次变化的值。
我们又知道,事件函数内的代码是在hmtl渲染结束之后执行的,因此事件函数内只能获取 i 的最后一次变化的值。
// 以下循环代码,循环内添加事件,事件内打印i的值
// 因为是在事件函数内打印i的值,此时循环必定已经结束,打印的 i 值一定是5.
for(var i=0;i<5;i++){
aBtn.onclick = function(){console.log(i)}
}
// 以下循环给多个div添加事件,原意是点击div让对应的div背景变红色。
// 但是因为事件函数触发时,i 的值统一是最大的那个值,因此导致错误的设置了不存在的div,导致报错。
// 解决办法是把var i=0 改成 let i = 0;至于为什么let没错,需要学到作用域才懂。
let aDiv = document.getElementsByTagName('div');
for(var i=0;i<arr.length;i++){
aDiv[i].onclick = function(){
aDiv[i].style.background = 'red'
}
}
5:嵌套循环
嵌套循环意即循环里面又有循环。嵌套循环由内循环和外循环组成。
内部循环的循环计数 j 不能和外部循环的循环计数 i 名字一致。
// 以下嵌套循环的意思是:
// 执行5次内部循环
// for(let j=0;j<5;j++){
// console.log(100);
// }
// 内部循环循环5次,内部循环代码体是console.log(100);
// 因此内部循环的意思是:
// 执行5次console.log(100);
for(let i=0;i<=4;i++){
for(let j=0;j<5;j++){
console.log(100);
}
}
// 分析得出,外部循环循环1次,内部循环循环5次。外部循环循环结束时,内部循环循环了25次。
// 或者理解为,内部循环总共循环25次,分5次执行。
何时用嵌套循环
// 例如遍历二维数组的所有元素
let arr = [[1,2,3],[4,5,6],[7,8,9]];
// 不用循环----------------------------------------------------------------
console.log(arr[0][0]);
console.log(arr[0][1]);
console.log(arr[0][2]);
console.log(arr[1][0]);
console.log(arr[1][1]);
console.log(arr[1][2]);
console.log(arr[2][0]);
console.log(arr[2][1]);
console.log(arr[2][2]);
// 不用嵌套循环---------------------------------------------------------------
for(let i=0;i<arr[0].length;i++){
console.log(arr[0][i]);
}
for(let i=0;i<arr[1].length;i++){
console.log(arr[1][i]);
}
for(let i=0;i<arr[2].length;i++){
console.log(arr[2][i]);
}
// 用嵌套循环-------------------------------------------------------------------
for(let j=0;j<arr.length;j++){
for(let i=0;i<arr[j].length;i++){
console.log(arr[j][i]);
}
}
6.
break => 终止整个循环。
continue => 跳过当前循环,继续后面的循环。
四 循环进阶
1.标志位
标志位 => 自定义的变量,用来做判断。初始值一般是布尔值。
// 写程序判断这个数组里面的元素是不是全都能整除3.能就弹出能,不能就弹不能.(弹一次);
const arr = [123,12,333,72];
let flag = true;
// 循环检测,如果有任意一个元素不能整除3,标准位变成false.
for (let i = 0; i < arr.length; i++) {
if (arr[i] % 3 !== 0) {
flag = false;
// 但凡有一个不能整除3,则后续所有的循环判断都没必要做了.
break;
}
}
if (flag) {
alert('能');
} else {
alert('不能');
}