JavaScript - 基础+WebAPI(笔记)

前言:

  • 求关注😭
    image.png
  • 本篇文章主要记录以下几部分:
    • 基础:
      • 输入输出语法;
      • 数据类型;
      • 运算符;
      • 流程控制 - 分支语句;
      • 流程控制 - 循环语句;
      • 数组 - 基础;
      • 函数 - 基础;
      • 对象 - 基础;
    • Web API:
      • DOM;
      • DOM事件基础(事件监听、常用事件、事件对象);
      • DOM事件进阶(事件流、事件委托);
      • 日期对象;
      • 节点操作;
      • M端事件;
      • JS插件;
      • window对象;
      • 本地存储;
      • 正则表达式;

  • 以下部分请移步JavaScript - 进阶+高级(笔记)
    • 进阶:
      • 作用域;
      • 函数进阶(函数提升、函数参数、箭头函数);
      • 解构赋值;
      • 对象进阶(构造函数、实例成员、静态成员);
      • 内置构造函数(Object、Array、String、Number);
      • 编程思想;
      • 构造函数;
      • 原型
    • 高级:
      • 深浅拷贝;
      • 异常处理;
      • this指向;
      • 性能优化(防抖、节流);

壹、❗❗ JavaScript基础

  • HTML 表示网页的 结构
  • CSS 表示网页的 样式
  • JavaScript 表示网页的 行为
  • 浏览器内核 = 渲染引擎 + JS引擎
  • JavaScript的组成
    • ECMAScript — JS的基础语法
    • Web APIs
      • DOM — 操作文档流的属性和方法(文档对象模型
        • 是HTML文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式,可以在程序中对该结构进行访问,从而改变文档的结构、样式和内容。DOM将文档解析为一个由节点和对象(包含属性和方法)组成的结构集合。简言之,它会将 web页面和 程序 连接起来。进而操作网页的内容,实现各种功能和部分特效
      • BOM — 操作浏览器的属性和方法(浏览器对象模型
      • image-20220912145005712
  • JS的本质: 通过 JS 的语法,让 浏览器 发生变换,让 文档 发生变化。

一、JavaScript书写位置

  • 行内 JavaScript
  • 内部 JavaScript
  • 外部 JavaScript

二、输入输出语法

  • 小括号里面只要 不是纯数字变量 必须要用 引号包裹(单、双、反)
    alert()			        ---  警示框
    prompt()			---  浏览器弹出输出框,用户可以输入信息
    console.log()			---  控制台输出
    document.write()		---  在文档页面输出(识别标签)
    
  • 代码展示:
    alert('你好, js');
    prompt('JavaScript 基础');
    console.log('它~会魔法吧~');
    document.write('javascript我来');
    

三、字面量、变量、常量

3.1 字面量

  • 用来在计算机中描述 事 / 物
  • [ ] : 数组字面量
  • { } : 对象字面量
  • 数字字面量:数字
  • 字符字面量:字符串
  • 布尔字面量:布尔值

3.2 变量

  • 变量:用来 存储数据容器
  • 变量的本质:内存里的一块空间,用来 存储数据
  • 变量 必须 先声明 后使用
  • 变量的初始化: 声明变量赋值
  • 变量命名规则:变量名只能是 数字大小写字母美元符($)下划线组成(⚠ 不能以数字开头)
  • ⚠ 不能使用 name 作为变量名 (name会将 数字型 转为 字符型)
  • 声明 变量使用 let
  • 代码展示:
    // 声明变量
    
    // 声明变量不赋值
    let a   
    
    // 变量的初始化  ---  声明变量并赋值
    let age = 18	
    
    // 声明多个变量(用逗号隔开)--- 不推荐
    let a = 18, b = 'pink'   
    
    // 更新变量
    let age = 18
        age = 19
    console.log(age)   // 19
    
    // 用变量赋值
    let myFood = '香蕉'
    let youFood = myFood
    console.log(youFood)	  // 香蕉
    
3.2.1 var 和 let 的区别
  • var
    • 可以 先使用 再声明
    • var声明过的变量可以重复声明
    • 存在变量提升、没有块作用域等等。
  • let / const
    • 必须 先声明 后使用
    • 不能 声明 重复变量
    • 不存在变量提升
    • 使用了 let / const 声明的变量存在块作用域
    • const声明变量的时候必须初始化

3.3 常量

  • 声明常量使用 const
  • ⚠ 常量不允许重新赋值声明的时候必须赋值 (必须初始化)
    • 注意:
      const num = 10;
      num = 10;
      console.log(num);	// 报错 - 常量不允许重新赋值
      

四、❗❗ 数据类型

  • 1️⃣ 值类型 (基本数据类型)(6)
    • number — 数字型
    • string — 字符串型
    • boolean — 布尔型
    • undefined — 未定义型
    • null — 空类型
    • symbol (了解)
    • bigint
  • 2️⃣ 引用数据类型 (复杂数据类型)(3)
    • object — 对象
    • function – 函数
    • array — 数组

4.1 数字型 - number

  • 数字型 = number + NaN
  • Number 一切十进制表示的数字
Number.MAX_VALUE    // 数字中的最大值
Number.MIN_VALUE    // 数字中的最小值
Infinity	    // 无穷大
-Infinity	    // 无穷小
NaN		    // 非数值

isNaN(数据) 这个方法用来判定非数字,并且返回一个值,如果是数字返回 false,如果不是数字返回 true
image-20220623195831594 + `NaN` 代表一个计算错误,它是一个不正确的或者一个未定义的数学操作所得到的结果 + ⚠ **`NaN` 是 粘性 的。任何对 `NaN` 的操作都会返回 `NaN`**
console.log(2 - NaN)	   // NaN
console.log('粘性' + NaN)  // NaN
console.log(NaN === NaN)   // NaN

4.2 字符串型 - string

  • 用引号(单引号 / 双引号 / 反引号)包裹的都是字符串
4.2.1 字符串的长度
lengtn 属性
let strMsg = (`扶我起来,我还能干!`) 
console.log(strMsg.length)		// 显示 10
4.2.2 字符串的拼接
  • 多个字符串之间可以使用 + 进行拼接,其拼接方式为 字符串 + 任何类型 = 新的字符串
  • 拼接前会把与字符串相加的任何类型转成字符串,再拼接成一个新的字符串
  • +数字相加,字符相连
4.2.3 ❗❗ 模板字符串
  • 使用 反引号(``) 包裹
  • 模板字符串可以 嵌套变量
    • 代码展示:
      let myName = `邵秋华`
      let age = 22
      let str = `扶我起来,我还能干!`
      document.write(`我叫${myName},今年${age}岁了,我的座右铭是${str}`)
      
4.2.4 ❌ 转义字符
image-20220623200802891

4.3 布尔型 - boolean

  • 布尔类型 有 两个值truefalse,其中 true 表示 ,而 false 表示
  • 布尔型数字型 相加 的时候,true = 1false = 0
  • ❗ 除了 0''undefinednullNaNfalse 转换为布尔值后为 ,其余都为真

4.4 未定义类型 - undefined

  • 只声明变量不赋值 的情况下,变量的默认值为 undefined
    • undefined 这里本该有一个值,但是没有,就是 undefined
  • 数字 + undefined = NaN
  • 注意:
    • ⚠ 对 undefined 的任何操作都是NaN,除了拼接字符串
  • 出现情况:
    • 声明变量未赋值
    • 数组 里面 没有 某个 元素
    • 对象 里面 没有 某个 属性 或 方法
    • 函数
      • 形参多于实参(没有赋值的形参默认值是 undefined)
      • 函数未指定返回值(没有 return 关键字)
console.log(undefind + 1)	    // NaN
condsole.log(undefined + 'purple')  // undefinedpurple
console.log(typeof(undefined))	    //undefined

4.5 空类型 - Null

  • Null 这里有一个值,有一个空值
  • ✅参与 数学运算 的时候,null = 0
console.log(null + 1)	        // 1
console.log(null + 'purple')    // nullpurple
console.log(typeof(null))	// object
image-20220623194305096

4.6 null 和 undefined 区别:

  • undefined 表示 声明了一个变量,但是没有赋值
    • let num
      console.log(undefined + 1)	// NaN
      
  • null 表示 声明了一个变量 并且 赋值了,但是内容为空
    • let num = null
      console.log(null + 1)	// 1
      
  • ✅注意:
    • nullundefined 值相等,数据类型不相等
    console.log(null == undefined)	// true
    

4.7 检测数据类型

  • 1️⃣ 作为运算符:typeof 数据
  • 以 字符串 的形式 给你变量的数据类型
  • ⚠ 使用 typeof 检测 错误类型 为 undefined 的代码不会报错,检测结果是 undefined
  • 2️⃣ 函数形式:typeof(数据)(推荐使用)
    • 以字符串的形式给你变量的数据类型
    • 先运算小括号里面结果,然后去检测结果的数据类型
    • 代码展示:
      let num = 10;
      console.log(typeof num);	  // number
      let str = 'purple';
      console.log(typeof str);	  //string
      let flag = true;
      console.log(typeof flag);     //boolean
      let i = undefined;
      console.log(typeof i);	  //undefined
      let timer = null;
      console.log(typeof timer);	  //object
      // 注意
      console.log(typeof (a));	  // undefined
      
  • 3️⃣ instanceof
    • 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
    • 返回值:布尔值(true / false)
  • 4️⃣ 究极方法: Object.prototype.toString()
    • 可以通过 toString() 来获取每个对象的类型。为了每个对象都能通过 Object.prototype.toString() 的检测,需要以 Function.prototype.call()Function.prototype.apply() 的形式来调用,传递要检查的对象作为第一个参数。
    • 返回值:[ object type ]
    • 代码展示:
      // 引用数据类型
      const obj = {uname: '迪迦', age: 22};
      console.log(Object.prototype.toString.call(obj));	// [object Object]
      const arr = [1, 2, 3];
      console.log(Object.prototype.toString.call(arr));	// [object Array]
      const fn = function () { console.log(1) };
      console.log(Object.prototype.toString.call(fn));	// [object Function]
      
      // 基本数据类型
      console.log(Object.prototype.toString.call(123));	// [object Number]
      console.log(Object.prototype.toString.call('123'));		// [object String]
      console.log(Object.prototype.toString.call(false) );	// [object Boolean]
      console.log(Object.prototype.toString.call(undefined));	// [object Undefined]
      console.log(Object.prototype.toString.call(null));		// [object Null]
      

4.8 数据类型转换

4.8.1 转数字
  • 1️⃣ parseInt(string) 可以把 字符串型 转换为 整数型不识别小数点
    • 第一个字符开始 取第一个整数,如果取不到就是NaN
    • ⚠ 转换的字符开头如果不是数字,就是NaN
    • 代码展示:
      console.log(parseInt('3.14'))	  //3(取整数位)
      console.log(parseInt('3.99'))	  //3(取整数位)
      console.log(parseInt('120px'))        //120 (自动去除单位,前面必须是数字)
      console.log((parseInt'rem120px'))     //NaN
      console.log(parseInt(true))		  //NaN
      console.log(parseInt(null));	  // NaN
      
  • 2️⃣ parseFloat(string) 可以把 字符串型 转换为 浮点型识别小数点
    • 第一个字符开始取第一个小数,如果取不到就是NaN
    • ⚠ 转换的字符开头如果不是数字,就是NaN
    • 代码展示:
      console.log(parseFloat('3.14'));	  //3.14
      console.log(parseFloat('3.99'));	  //3.99
      console.log(parseFloat('120px'));     //120 (自动去除单位,前面必须是数字)
      console.log(parseFloat('rem120px'));  //NaN
      console.log(parseFloat(true))	  //NaN
      console.log(parseFloat(null));	  // NaN
      
    • ⚠ 注意:
      parseInt 和 parseFloat 单词的大小写
      
  • 3️⃣ Number(string) 强制转换
    • 转换的数据中不能包含非数字,如果有就是NaN
    • 识别小数点
    • 代码展示:
      let num = '123';
      console.log(Number(num));			  //123
      console.log(Number('12')); 		 	//12
      console.log(NUmber('123.123');	       // 123.123
      console.log(Number('123abc');		//NaN
      console.log(Number(null));			// 0
      console.log(Number(true));			// 1
      console.log(Number(false));			// 0
      
  • 4️⃣ 利用了算术运算 **+(正号) - * / % ** 隐式转换
    • 代码展示:
      console.log('12' - 0);	  //12	(先将 '12' 转换成数字型在进行减)
      console.log('123' - '120');		//3
      console.lof('123' * 1);		  //123
      console.log(+'123')			//123
      + 号作为正号解析可以转换成数字型(单用)
      
      let year = prompt('请输入您的出生年份:');
      //let age = 2022 - year;
      alert('您今年:' + (2022 - year) + '岁了');
      
    • 注意:
      • 隐式转换是我们在进行算数运算的时候,JS 自动转换了数据类型
      • 代码展示:
        let num1 = prompt('请输入第一个数据:');	//得到的num1是字符型的
        let num2 = prompt('请输入第二个数据:');	//得到的num2是字符型的
        let result = parseInt(num1) + parseInt(num2);
        alert(parseInt(num1) + '+' + parseInt(num2) + '=' +  result);
        
        /*
        let num1 = +prompt('请输入第一个数据:');	
        let num2 = +prompt('请输入第二个数据:');	
        let result = num1 + parseInt(num2);
        */
        
image-20220624101901837
  • 注意:
    • 有字符串的加法 ‘’ + 1,结果是 ‘1’
    • 减法 只能用于数字,它会使 空字符串 ‘’ 转换为 0
    • null 经过 数字转换 之后会变为 0
      • parseInt(null);		// NaN
        parseFloat(null);	// NaN
        Number(null);		// 0
        
    • undefined 经过 数字转换 之后会变成 NaN
    • undefined 做任何操作都是 NaN 除了拼接字符串
    null == undefined	// true 值都是空
    null === undefined  // false 数据类型不一样
    
    image-20220727173543226
4.8.2 转字符串
  • 1️⃣ String(数据)
    • 返回值:转换好的数据
    • 代码展示:
      console.log(String(123))		// '123'
      
  • 2️⃣ 数据.toString()
    • 返回值:转换好的数据
    • ⚠ **注意:**需要 配合 变量 使用、
    • 代码展示:
      let num = 123
      console.log(num.toString())  // '123'
      
  • 3️⃣ +(加号)
    • 字符串的拼接
    • 代码展示:
      console.log(123 + '')				// '123'
      
image-20220623205607781
toString()String()  使用方式不一样。
三种转换方式,我们更喜欢用第三种加号拼接字符串转换方式, 这一种方式也称之为隐式转换。
4.8.3 转布尔
  • Boolean(数据)
    • 返回值:转换好的数据
    • ⚠ 注意:代表 、**否定的值 **会被 转换成 false
      • ‘’、 0、 NaN、 null、 undefined、 false
    • 代码展示:
      console.log(Boolean(''))		// false
      console.log(Boolean(0))		// false
      console.log(Boolean(NaN))		// false
      console.log(Boolean(null))		// false
      console.log(Boolean(undefined))	// false
      console.log(Boolean(false))		// false
      
      注意:
      // 两个等号值比较 值
      // null 和 undefined 都是空
      console.log(null == undefined)	// true
      

五、运算符

5.1 算术运算符

image-20220624103954490 + ⚠ **注意:** + 取余前面的数比后面的小,余数就是前面的数

5.2 递增递减运算符

5.2.1 前置++
  • 先自加,后返回值
  • 先自加,后运算(++在前 先加
let  num = 10;
alert(++num + 10);   // 21
5.2.2 后置++
  • 先原值运算,后自加(++在后 后加
  • 先表达式返回原值,后面变量再自加1
let  num = 10;
alert(10 + num++);  // 20
  • **注意:**前置++ 和 后置++ 单独书写没有差别
5.2.3 前置–
先自减,后运算(先已后人)
let  num = 10;
alert(--num + 10);   // 19
5.2.4 后置–
先原值运算,后自减(先人后己) 
let  num = 10;
alert(10 + num--);  // 20
let a = 10;
++a;              // ++a = 11  a = 11
let b = ++a + 2;  // a = 12    ++a = 12
console.log(b);   // 14

let c = 10;
c++;		  // c++ = 11  c = 11
let d = c++ + 2;  // c++ = 11  c = 12
console.log(d);	  // 13

let e = 10;
let  f = e++ + ++e;
// e++ = 10   e = 11
// e = 12    ++e = 12
console.log(f);	   // 22

5.3 比较运算符

image-20220624104610215
  • 注意:
    • 比较运算符有隐式转换
    • console.log(2 == '2')		// true
      
  • 特殊说明:
    • 如果是数字和“其他值”的比较,则其他值会自动转换成数字去比较
    • 涉及到“NaN”都是false
    • 如果是”字符串“和“字符串”比较,则会比较每一个字符的ASCII码
    • 如果是布尔值参与比较,布尔值会自动转换成数字0和1
    • 数字只有0是假,其余为真
    • 字符串只有’'(空字符串)是假,其余都为真

5.4 ❗ 逻辑运算符

image-20220707185825834
  • 1️⃣ && 与 有 一个 是 false ,得到的 结果 就是 false ;只有 两侧 都是 true 的时候,才可以到的 true
  • 2️⃣ || 或 有一个 是 true ,得到的结果就是 true ;只有 两侧 都是 false 的时候,才得到 false
  • 3️⃣ ! 非 取反(双取反可以转布尔)
  • 注意: 逻辑运算符 优先级: ! > && > ||
5.4.1 短路运算(逻辑中断)
  • 短路运算的原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值;
  • 1️⃣ 逻辑与-语法:(一假则假
    • 表达式1 && 表达式2
      	 如果 表达式1的值 为 真,则返回 表达式2
         如果 表达式1的值 为 假,则返回 表达式1 (后面的表达式不再执行)
      	 两侧都为真,返回第二个
      
  • 2️⃣ 逻辑或-语法: (一真则真
    • 表达式1 || 表达式2
      	 如果 表达式1的值 为 真,则返回 表达式1 (后面的表达式不再执行)
         如果 表达式1的值 为 假,则返回 表达式2 
         两侧都为真返回第一个
      

5.5 赋值运算符

image-20220624104834906

5.6 ❗ 运算符优先级

  • 一元运算符逻辑非 优先级最高
  • 逻辑与逻辑或 优先级
    image-20220624105604315
  • console.log( 4 >= 6 || '人' != '阿凡达' && !(12 * 2 == 144) && true)  // true
    let num = 10
    console.log( 5 == num / 2 && (2 + 2 * num).toString() ===22)		// true
    let a = 3 > 5 && 2 < 7 && 3 == 4 
    console.log(a)  		// false
    let b = 3 <= 4 || 3 > 1 || 3 != 2 
    console.log(b) 		// true
    let c = 2 === "2" 
    console.log(c)  		// false
    let d = !c || b && a 
    console.log(d)		// true
    

六、流程控制 - 分支语句

  • 表达式和语句的区别:
    • 表达式:表达式可被求值,可以写在赋值语句的右侧(运算符和数据组成的式子)
    • 语句:不一定有值(可以被执行的代码)

6.1 if 语句

  • 条件为 true 的时候,大括号里面的代码才会执行

  • 小括号里的结果若不是布尔类型时,会发生隐式转换转为布尔类型

  • ⚠ if分支语句,如果前面的条件被满足,后面的代码就不执行了

  • if (条件) {
      满足条件要执行的代码
    }
    
  • if (条件) {
      满足条件要执行的代码
    } else {
      条件不满足时要执行的代码
    }
    
    eg:
    // 能被4整除但不能被100整除,或者被400整除的年份是闰年,否则都是平年
    let year = +prompt('请输入年份:')
    if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
      alert(`&{year}是闰年`)
    } else {
      alert(`&{year}是平年`)
    }
    
  • if (条件表达式1) {
      满足条件1要执行的代码
    } else if (条件表达式2) {
      满足条件2要执行的代码
    } else if (条件表达式n) { 
      满足条件n要执行的代码
    } else {
      所有条件都不满足时要执行的代码
    }
    

6.2 三元运算符

  • 语法结构:
    条件表达式 ? 表达式1 : 表达式2
    
  • 执行思路:
    • 如果 条件表达式 结果 为真,则 返回 表达式1 的值,如果 条件表达式 结果 为假,则 返回 表达式2 的值
  • 代码展示:
    let time = prompt('请您输入一个 0 ~ 59 之间的一个数字')
    // 三元表达式 表达式 ? 表达式1 :表达式2 
    let result = time < 10 ? '0' + time : time // 把返回值赋值给一个变量
    alert(result)
    
    /* 如果输入的数字小于10,就在该数字前面加一个0,否则原样输出该数字 */
    let num = prompt('请输入数字:')
    let result = num < 10 ? '0' + num : num
    alert(result)
    

6.3 switch 语句

  • 表达式有一个返回值,**返回值 **会和 value 做匹配(必须是 全等 的关系),如果匹配上了就执行对应的语句 ,如果都匹配不上就执行default里的语句
  • 语法:
    switch ( 表达式 ) {
    	case value1:
    	满足value1执行的代码
    	break
    	case value2:
    	满足value2执行的代码
    	break
    	default:
    	所有条件都不满足时要执行的代码
    }
    
  • 注意:
    • 每一个 case表达式 必须是 ===数据类型 都相等) 才叫满足
    • switch 语句,只能判断一些准确的值,不能判断范围
    • 实际开发过程中 表达式 我们经常 写成 变量
    • 代码展示:
      let num1 = +prompt('请输入第一个数字:')
      let sp = prompt('请输入 + - / * 其中一个:')
      let num2 = +prompt('请输入第二个数字:')
      
      switch (sp) {
        case '+':
          let add = num1 + num2
          alert(`${num1} + ${num2} = ${add}`)
          break
        case '-':
          let dif = num1 - num2
          alert(`${num1} - ${num2} = ${dif}`)
          break
        case '*':
          let bus = num1 * num2
          alert(`${num1} x ${num2} = ${bus}`)
          break
        case '/':
          let pro = num1 / num2
          alert(`${num1} ÷ ${num2} = ${pro}`)
          break
        default:
          alert('请输入正确的运算符')
          break
      }
      

七、流程控制 - 循环语句

7.1 循环成立的条件

  • 初始值 作为循环的开始
  • 条件判断 决定要不要继续循环
  • 要重复执行的代码
  • 改变初始值 为了让循环有结束

7.2 ❗ for 循环

  • 语法结构:
    for (初始化变量; 条件表达式; 操作表达式) {
        循环体
    }
    
  • 初始化变量:通常被用于初始化一个计数器,这个变量帮我们来记录次数。
  • 条件表达式:用于确定每一次循环是否能被执行。如果结果是 true 就继续循环,否则退出循环。(终止条件)
  • 操作表达式:每次循环的最后都要执行的表达式。通常被用于更新或者递增计数器变量。当然,递减变量也是可以的。(递增或者递减)
  • 代码展示:
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    
    <body>
    
    </body>
    
    <script>
      // 求1-100之间所有数字的和
      let  sum = 0;
      let average = 0;
      for (let i = 1; i<= 100; i++) {
          sum += i
      }
      average = sum / 100;
      console.log('1-100之间所有数字的和为:' + average); 
    
      // 求1-100之间所有偶数的和和奇数的和
      let even = 0;
      let odd = 0;
      for (i = 1; i <= 100; i++) {
        // 第一种
        if (i % 2 == 0) {
          even = even + i;
        } else {
          odd += i;
        }
        
        //第二种
        if (i % 2 == 0) {
          even = even + i;
        }
        odd = sum - even;
      }
      console.log('1-100之间所有偶数的和为:' + even + '\n' + '1-100之间所有奇数的和为:' + odd);
    
      // 求1-100之间所有能被3整除的数字的和
      let odd_num = 0;
      for (let i = 1; i <= 100; i++) {
          if (i % 3 == 0) {
              odd_num = odd_num + i;
          }
      }
      console.log('1-100之间所有能被3整除的数字的和为:' + odd_num);
      
      //弹出输入框,输入一共有n个学生,然后弹出n个输入框,输入每个学生的成绩,最后输出总成绩和平均成绩
      let frequency = prompt('请输入有多少个学生:');
      let score = 0;
      for (let i = 1; i <= frequency; i++) {
          let a = prompt('请输入第' + i + '个同学的成绩:');
        // 从 prompt 获取到的数据是 String 类型的,不能直接和数字进行相加
          score = score + parseFloat(a);
       }
      alert('该班总成绩是:' + score);
      alert('该班平均成绩是:' + (score / frequency));
    
      //一行打印五个星星
      let str = ' ';
      for (let i = 1; i <=5; i++) {
              str = str + '⭐';
      }
      console.log(str);
    </script>
    </html>
    
    image-20220628205809445
image-20220628213008738

7.3 ❗ 双重for循环

  • //打印n行m列的星星
    let rows = +prompt('请输入需要打印几行的星星:');
    let cols = +prompt('请输入需要打印几列的星星:');
    let str = '';
    for (let i = 1; i <=rows; i++) {
      for (let j = 1; j <= cols; j++) {
        str +=  '⭐';
      }
      str += '\n';
    }
    console.log(str);
    
image-20220630110759649
  • 冒泡排序:
    // 外层for循环:控制已经排序好的元素的个数
    // 内层for循环:控制每排序好一个元素需要比较几次
    const arr = [1, 7, 3, 9, 5, 2, 6, 4, 8];
    for (let i = 0; i < arr.length - 1; i++) {
      for (let j = 0; j < arr.length - i - 1; j++) {
        if (arr[j] > arr[j + 1]) {
          let temp = arr[j + 1];
          arr[j + 1] = arr[j];
          arr[j] = temp;
        }
      }
    }
    console.log(arr);
    

7.4 while循环

  • 循环三要素:
    • 变量初始值
    • 终止条件
    • 变量变化量
  • 语法:
    let n = 1
       while ( 循环条件 ) {
           重复执行的代码
           n++
       }
    

7.5 ❗ continue 和 break

  • continue
  • 退出本次循环,继续下一次循环
  • 一般用于排除或者跳过某一个选项的时候
  • continue 在循环节构中用来跳过本次循环中剩余的代码,并且在条件求值为真的时开始下一次循环。
  • 不能省略 continue 后面的分号(导致胡乱)
  • continue 后面 的 代码 不会 再 执行
  • break
  • 退出整个循环(结束循环)
  • 一般用于结果已经得到,后续的循环不需要的时候
  • 在一些计算机语言中 break 是保留字,其作用大多数情况下是终止上一层循环。

7.6 JS标记语法

  • JS标记语法
    here:
    for (let i = 1; i <= 5; i++) {
      for (let j = 1; j <= 3; j++) {
        if (i === 3 && j === 2) {
          console.log('看到半条虫子')
          break here
        }
        console.log('吃的第 ' + i + ' 个包子得第 ' + j + ' 口')
      }
      console.log('=================')
    }
    

八、❗❗ 数组 - 基础

  • 一种 有序 的数据集合

8.1 创建数组

8.1.1 字面量创建
let 数组名 = [数据1, 数据2,, 数据n]
let arr = ['name', 'Jack', 'age', 20, 'gender', '男'] 
8.1.2 内置构造函数创建
//没有参数表示空数组
let arr = new Array()  

//一个参数表示数组的长度
let arr = new Array(100) 

//多个参数表示都是数组里面的数据,没有表示长度的参数
let arr = new Array(10, 20, 30) 
arr.length = 2				//删除最后一个
arr.length = 5				//后面的两个用空补齐
console.log(arr[2])		//读取里面的额第三个数据

8.2 ❗❗ 遍历数组

能够获取数组里面的每个元素

8.2.1 for
  • 格式:
    for (let i = 0; i < 数组名.length; i++) {
      // 执行的操作
      // console.log(数组名[i])
    }
    
8.2.2 forEach
  • 取代 for 循环
  • 语法:
    数组.forEach(function (item, index, arr) {  } )
      -> item :数组里面的每一项
      -> index :数组里面每一项的索引
      -> arr : 原始数组
    
  • 没有 返回值
  • forEach中的 return 等同于 for循环的 continue
  • 终止forEach循环:try - catch
    try {
      [1, 2, 0, 3].forEach(item => {
        console.log(item)
        if (item === 1) {
          console.log(item)
          throw Error()
        }
      })
    } catch (error) {
      console.log('终止循环')
    }
    
    // 打印结果
    // 1
    // 1
    // z
    
8.2.3 for of
  • 遍历 可迭代 的数据:数组,伪数组,字符串
  • 遍历的是数组、伪数组、字符串的值
  • 语法:
    for (let item of arr) {
      console.log(item)		//  item -> 数据里面的每一项
    }
    

8.3 数组的增删查改

8.3.1 增
  • 1️⃣✔数组.push() 方法:将 一个或多个元素 追加 **到 数组末尾 ,并 返回 追加元素后数组长度
    • 语法:数组.push(数据1, 数据2, … ,数据n)
    • 返回值: 追加元素后数组的长度
    • 改变原始数组
  • 2️⃣ 数组.unshift() 方法:将 一个或多个元素 插入数组开头,并 返回 插入元素后数组长度
    • 语法:数组.unshift(数据1, 数据2, …, 数据n)
    • 返回值: 插入元素后数组的长度
    • 改变原始数组
  • 见代码展示
8.3.2 删
  • 1️⃣ 数组.pop() 方法:从数组中 删除 最后一个 元素
    • 语法:数组.pop()
    • 返回值: 被删除的元素
    • ⚠改变原始数组
  • 2️⃣ 数组.shift() 方法:从数组中 删除 第一个元素
    • 语法:数组.shift()
    • 返回值: 被删除的元素
    • 改变原始数组
  • 3️⃣ ✔数组.splice(start, deleteCount) 方法:删除 数组 里 指定的元素
    • 语法:数组.splice(开始索引,删除几个)
      • ⚠🔺 注意:包含开始索引 对应元素
      • deleteCount:表示要移除的数组元素个数(如果 省略默认指定的起始位置 删除到最后
    • 返回值: 新数组(将删除的元素放到这个新数组里面)
    • 改变原始数组
  • 见代码展示
8.3.3 查
  • 见代码展示
8.3.4 改
  • 见代码展示
代码展示:
<script>
  let arr = ['pink', 'red'];
  // 增加
    // 方案一:数组.push()方法
        语法:arr.push(元素1, 元素2,, 元素n);
        追加数组 的同时 有一个 返回值 是 追加以后 的 数组长度
        console.log(arr.push('green', 'hotpink', 'deeppink'));	// 5
        console.log(arr); 
	// ['pink', 'red', 'green', 'hotpink', 'deeppink']
		
    // 方案二:数组.unshift()方法
        语法:arr.unshift(元素1, 元素2,, 元素n);
        console.log(arr.push('green', 'hotpink', 'deeppink'));	// 5
        console.log(arr);
        // ['green', 'hotpink', 'deeppink', 'pink', 'red']
	
 // 删除
    // 方案一:数组.pop()
        console.log(arr.pop());		// green
    // 方案二:数组.shift()
        console.log(arr.shift());	// red
    // 方案三:数组.splice(起始位置的索引, 删除几个元素)
        // 从索引号0的位置开始,删除两个元素
        console.log(arr.splice(0, 2));	// ['hotpink', 'deeppink']

 // 查询 --- 利用数组的索引进行查找
        console.log(arr[0]);	// pink

 // 修改 --- 利用 对数组进行遍历,然后和字符串拼接,重新赋值给数组里的元素
    // 方案一:
    arr[0] = 'blue';
    arr[1] = 'purple';

    //方案二:
    for (let i = 0; i < arr.length; i++) {
        arr[i] += '老师';
    }
    console.log(arr)
</script>

九、❗❗ 函数

  • 函数:执行特定任务的代码块

9.1 函数的声明和使用

9.1.1 函数的声明
  • 函数命名规范:
    • 和变量命名基本一致
    • 小驼峰式命名法
    • ⚠ 前缀应该为动词
      • can		---		判断是否可执行某个动作
        has		---		判断是否含义有某个值
        is		---		判断是否为某个值
        get		---             获取某个值
        set		---		设置某个值
        load	        ---		加载某些数据
        
  • 1️⃣ 具名函数
    • 语法
      function 函数名() {
        函数体
      }
      
    • ⚠ 注意:可以 后声明先调用 ,也可以 先声明后调用
  • 2️⃣ 匿名函数
    • 使用方式:
      • 函数表达式:
        • 语法:
          let 函数名 = function () {
              // 函数体
          }
          
      • 立即执行函数:
        • 语法:
          !(function (实参) { 函数体 })(实参);
          !(function (实参) { 函数体 } (实参));
          
        • 注意: 立即执行函数 末尾 必须加 分号
    • 注意:
      • 函数名() — 表示调用这个函数
      • 函数名 — 表示一个变量,代表这个函数
  • 代码展示:
    function getSum() {
      let sum = 0
      for (let i =  1; i <= 100; i++) {
        sum += sum
      }
      document.write(sum)
    }
    
9.1.2 函数的使用
  • 函数的调用:
    • 函数名()
      
  • 注意: 声明的函数 必须 调用 才会真正执行,使用 () 调用函数
  • 函数 一次声明 可以 多次调用 ,每一次函数调用函数体里面的代码会重新执行一次
    • 代码展示:
      function getSum() {
        let sum = 0
        for (let i =  1; i <= 100; i++) {
          sum += sum
        }
        document.write(sum)
      }
      getSum()	// sum = 5050
      
9.1.3 函数传参
  • 声明语法:
    • function 函数名(参数列表) {
        函数体
      }
      
    • 传入数据列表
    • 声明这个函数需要传入几个数据
    • 多个参数之间用 逗号 隔开
    • 代码展示:
      function getSum(start, end) {
        // 形参 - 形式上的参数
        let sum = 0
        for (let i =  start; i <= end; i++) {
          sum += sum
        }
        document.write(sum)
      }
      
  • 调用语法:
    • 函数名(传递的参数列表)
      
    • 代码展示:
      getSum(10, 20)	// sum = 33
      // 实参 - 实际的参数
      
    • 形参
      • 形式上的参数 — 写在 函数声明阶段小括号
      • 本质:就是在函数内部声明的变量(局部变量)
      • 作用:接受实参传递的参数
      • 如果既没有实参传递,也没有设置默认值,就是 undefined
    • 实参
      • 实际上的参数 — 写在 **函数调用阶段 **的 **小括号 **里
      • 实参 可以是 变量
      • 作用:给形参赋值
  • 参数默认值:
    • 在调用的过程中,如果有参数传递过来,就用传递过来的;如果没有参数传递过来就用默认的
    • ⚠ **注意:**若没设置默认值,默认就是 undefined
    • 代码展示:
      function getSum(x = 0, y = 0) {
        // 小括号里写了就不用写
        // 推荐用逻辑中断
        // x = x || 0
        // y = y || 0
        document.write(x + y)
      }
      
      getSum()	// 0
      getSum(1, 2)   // 3
      
9.1.4 函数的返回值:
  • 语法:返回给调用者(当调用某个函数,这个函数会返回一个结果出来)
    return 要返回的数据
    
  • 注意:
    • 函数体 中使用 return 关键字能 将内部的执行结果 交给 函数外部 使用
    • 所以 return 后面的数据不要换行写
      • ⚠ return 和 要返回的数据不能换行写(模板字符串、函数除外)
    • 一个函数只能有一个return(因为第一个return后面的代码就不执行了)
    • 如果 函数 没有指定 return,这种情况函数 默认返回值undefined
    • 函数如果有 多个返回值 ,用 中括号包裹中间逗号隔开返回的是一个新数组
  • 代码展示:
    • function fn() {
          return 20   // 把 结果(20) 返回给 fn
      }
      fn()  // 相当于执行了 fn() = 20	(fn()是函数的调用者)
      console.log(fn())	// 20
      
      // 求两个数的最大值
      function getMax(x = 0, y = 0) {
        return x > y ? x : y
      }
      
      getMax(65, 99)	// 99
      let max = getMax(65, 99)
      console.log(max)	
      
    • 求数组里面的最大值和最小值
    • 代码展示:
      // 声明一个 getArrValue函数
      function getArrValue(arr = []) {
        let max = arr[0]
        let min = arr[0]
        //遍历数组
        for (let i = 0; i < arr.length; i++) {
          // 最大值
          if (max < arr[i]) {
            max = arr[i]
          }
      		
          // 最小值
          if (min > arr[i]) {
            min = arr[i]
          }
        }
      	
        // return 返回多个值写法
        return [max, min]
      }
      
      let newArrr = getArrValue([23, 56, 32, 198, 0, 5, -98])
      
      console.log(`数组中的最大值是:&{newArr[0]}`)		// 198
      console.log(`数组中的最小值是:&{newArr[1]}`)		// -98
      
      • 时间转换 + 补0
      • 代码展示:
        function getTime(t = 0) {
          let second = parseInt(t % 60)
          let minute = parseInt(t / 60 % 60)
          let hour = parseInt(t / 60 / 60 % 24)
        
          // if条件分支语句
          /*  if (second < 10) {
                  second = '0' + second
              }
        
              if (minute < 10) {
                  minute = '0' + minute
              }
        
              if (hour < 10) {
                      hour = '0' + hour
              } */
        
          // 三元表达式
          second < 10 ? second = '0' + second : second
          minute < 10 ? minute = '0' + minute : minute
          hour < 10 ? hour = '0' + hour : hour
        
          return `${t}秒 = ${hour}小时${minute}分钟${second}`
        }
        
        let str = getTime(+prompt('请输入秒数:'))	// 1000
        document.write(str)		// 1000秒 = 00小时16分钟40秒
        
  • 函数注意点:
    • 两个函数名相同的函数,后面的会覆盖前面的
    • 两个函数体相同的匿名函数不是同一个函数
    • 传递参数
      • 形参过多会自动填上 undefined
      • 实参多于形参,剩余的实参不参与运算
      • 实参少于形参,多于的形参使用默认值 undefined
    • 函数一旦碰到 return 就不会往下执行,函数的结束用 return
  • break 和 return 的区别:
    • break结束 的是 循环 和 switch
    • return结束 的是 函数for循环

9.2 作用域基础

作用域: 变量的 可用性范围 就是 作用域 (提高程序逻辑的局部性)

9.2.1 全局作用域
  • 全局有效
  • 作用与所有代码执行的环境(整个script标签内部)或者一个独立的js文件
9.2.2 局部作用域
  • 局部有效
  • 作用与函数内的 代码环境,就是局部作用域。因为跟函数有关,所以也称为函数作用域
9.2.3 特殊
  • 如果函数内部,变量没有声明,直接赋值。也当全局变量看。不推荐
    • 代码展示:
      function fn() {
        num = 10	// 全局变量来看
      }
      
      fn()									
      console.log(num)	// 10
      
  • 函数内部的 形参 可以看作是 局部变量
    • 代码展示:
      function fun(x, y) {
        // 形参可以看做是函数的局部变量
        console.log(x)	// 1
      }
      fun(1, 2)				
      console.log(x)	// x is not defined (报错)
      

9.3 变量的访问原则

  • 只要是代码,就至少有一个作用域
  • 写在函数内部的局部作用域
  • 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域
  • 访问原则就近原则):在能够访问到到的情况下 先局部,局部没有 再找全局 (由内向外)
    • 代码展示:

      functin f1 () {
        let num = 123
        function f2 () {
          console.log(num)	//   123
        }
        f2()
      }
      let num = 456
      f1()						
      
      function f1() {
        let num = 123
        function f2() {
          let num = 0
          console.log(num)	//  0
        }
        f2()
      }
      let num = 456
      f1()				
      
      let a = 1
      function fn1() {
        let a = 2
        let b = '22'
        function fn2() {
          let a = 3
          fn3()
          function f3() {
            let a = 4
            console.log(a)	//  a的值 = 4
            console.log(b)	//  b的值 = '22'
          }
        }
      }
      fn1()
      

9.4 匿名函数

  • 没有名字的函数,无法直接使用
  • 使用方式: 函数表达式 / 立即执行函数
    • 1️⃣ 函数表达式:
      • 函数表达式:将匿名函数赋值给一个变量,并且通过变量名称进行调用
      • 语法:
        let 变量名 = function () {
          // 函数体
        }
        
      • 调用:变量名()
      • 代码展示:
        let fn = function () {
          console.log('我是函数表达式')
        }
        fn()  //  我是函数表达式
        
      • ⚠🔺 注意: 函数表达式 必须 声明 调用
        • 因为变量必须先声明后使用
    • 2️⃣ 🔻**立即执行函数:**避免全局变量的污染(防止变量污染(冲突)
      • 函数声明后立即执行,并且执行完一次后被释放
      • 语法:
        // 写法一:
        (函数)();		
        
        // 写法二:
        (函数 ());	
        
      • ⚠ 立即执行函数 必须 分号
      • 立即执行函数可以传递参数
      • 先写两个小括号,前面的小括号写函数
      • 可以给匿名函数添加函数名
      • 最后面的小括号相当于调用函数
        • 代码展示:
          (function () {
            console.log('立即执行函数')
          })();
          // 保存之后会在控制台立即打印 '立即执行函数'
          
          // 第一种写法:
          (function () {
              console.log('立即执行函数第一种写法');
          })();
          
          (function (x, y) {	// (x, y) --->   形参
            console.log(x, y);	// x = 5; y = 9
          })(5, 9);		// (5, 9) --->   实参
          
          
          // 第二种写法:
          (function () {
              console.log('立即执行函数第二种写法');
          } ());
          
          (function (x, y) {	// (x, y) --->   形参
            console.log(x, y);	// x = 5, y = 9
          } (5, 9));	// (5, 9) --->   实参
          

9.5 具名函数 和 匿名函数 的区别

  • 具名函数:
    • 可以 先调用 后声明,也可以 先声明 后调用
    • 具名函数 的 调用 可以 写在 任意位置
  • 匿名函数
    • 函数表达式必须 先声明函数表达式 后调用
    • 匿名函数 的 调用 必须写在 声明函数 的 后面

9.6 函数中的逻辑中断

  • 函数的默认值
    • 方案一:(赋值)
      function fn(x = 0, y = 0) {
        x = x
        y = y
        console.log(x, y)
      }
      fn(1, 2)	// x = 1, y = 2
      fn()	// x = 0, y = 0
      
    • 方案二:(逻辑中断)(推荐)
      function fn(x, y) {
        x = x || 0
        y = y || 0
        console.log(x, y)
      }
      fn(1, 2)	// x = 1, y = 2
      fn()	// x = 0, y = 0
      

十、❗❗ 对象 - 基础

  • 对象 = 属性 + 方法

10.1 对象 - object

  • 对象是一种复杂数据类型
  • 一种 无序 的数据集合(不可迭代)

10.2 使用对象

10.2.1 声明对象
  • 语法:
    • let 对象名 = {}
    • let 对象名 = new Object()
    let obj = {}		// 声明了一个obj的对象
    let obj = new Object();
    
  • 组成:属性 + 方法
    let 对象名 = {
    	属性名: 属性值,
      方法名: 函数
    }
    
    eg:
      let obj = {
       uname: 'pink老师',
       age : 18,
       gender: '男'
     }
      console.log(obj)
      // {uname: 'pink老师', age: 18, gender: '男'}
    
    • 属性都是 成对 出现的,包括 属性名属性值 ,它们之间使用英文 : 分隔
    • 对象属性没有顺序
    • 多个属性之间使用英文 , 分隔
    • 属性就是依附在对象上的变量(外面变量对象内属性
    • ⚠ 属性名可以使用 " "’ ’ ,一般情况下省略,除非名称遇到特殊符号如 空格 、 中划线 等
      • 属性名 不能 使用 反引号
10.2.2 增删查改
  • 1️⃣
    • 语法:
      • 对象名.属性名
      • 对象名[‘属性名’] (🔺 属性名 必须 引号
        • ⚠ 如果属性名存放在一个 变量 里面,只能使用 数组关联语法
    • 代码展示:
      console.log(obj.uname)	// pink老师
      console.log(obj['uname'])	// pink老师
      
  • 2️⃣
    • 语法:对象名.属性名 = 新值
    • 代码展示:
      obj.gender = '女'
      console.log(obj.gender)	// 女
      
  • 3️⃣
    • 语法:对象名.新属性名 = 新值
      obj.address = '武汉黑马'
      console.log(obj)	// {uname: 'pink老师', age: 18, gender: '女', address: '武汉黑马'}
      console.log(obj.address)	// 武汉黑马
      
  • 4️⃣删(了解)
    • 语法:delete 对象名.属性名
      delete obj.address
      console.log(obj)	// {uname: 'pink老师', age: 18, gender: '女'}
      
10.2.3 对象的方法
  • 方法 = 方法名 + 函数,它们之间用 : 分隔
  • 多个属性 之间 使用英文 , 分隔
  • 方法是依附在对象中的函数(外面函数对象内方法
  • 方法名可以使用 “”‘’ ,一般情况下省略,除非遇到特殊符号如 空格、中划线 等
  • 声明对象,并添加了若干方法后,可以使用,调用 对象 中的 (方法)函数,我们称之为方法调用
    • 语法:对象名.方法名()
    • 千万别忘了给方法名后面加 小括号
  • 代码展示:
    let obj = {
      uname: '刘德华',
      // 方法
      song: function () {
        console.log('冰雨')
      },
      getSum: function (x, y ) {
        x = x || 0
        y = y || 0
        console.log(x + y)
      }
    }
    
    // 方法调用 对象名.方法名()
    obj.song()				// 冰雨
    obj.getSum(2, 5)	// 7
    

10.3 ❗ 遍历对象

  • 1️⃣ for in 语法
    • 遍历的是 对象的属性 / 数组的索引 / 伪数组的索引 / 字符串的索引
      • 得到的索引都是字符串型
    for (let k in obj) {
      console.log(obj[k])
    }
    
    • 结论: k 是获得 对象属性名对象名[k] 是获得 对象属性值
  • 2️⃣ 判断一个成员在不在对象里面
    • 语法:
      属性/方法 in 对象名
      
    • 返回值: 布尔值 (true / false)
    • 代码展示:
      let obj = {
        uname: 'jack',
        age: 18,
        gender: '男',
        score: 100
      };
      console.log('name' in obj);	// true
      
  • 代码展示:
    //声明一个 obj 对象
    let obj = {
      uname: 'pink老师',
      age: 18,
      gender: '男'
    }
    
    // 用 fou in 循环遍历对象
    for (let k in obj) {		
      // k 可以是任何变量,选择 k/key 是因为许多程序员都在使用
      
      // console.log(k)      
      // k 是字符串型的,带有引号
      // k => 'uname' 'age' 'gender'
      // obj 对象里面没有 'uname'、 'age'、 'gender' 的属性名   ------    有引号
      // obj 对象里面的属性名是 uname、 age、 gender            ------    没有引号
      // 查询对象里面的属性有两种方法:1)对象名.属性名
      // 													2)对象名['属性名']
      // 原因:obj[k] === obj['uname'] === obj.uname
      //      obj[k] === obj['age'] === obj.age
      //	   obj[k] === obj['gender'] === obj.gender
      // 所以,利用for in循环遍历对象采用第二种查询方法
      // 结论:k 是获得对象的属性名 , 对象名[k] 是获得 属性值
      
      console.log(obj[k])	// 'pink老师'(string)  18(number)  '男'(string)
    }
    
  • 渲染学生信息
    • 代码展示:
      <!DOCTYPE html>
      <html lang="en">
      
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Document</title>
          <style>
          table {
              width: 600px;
              text-align: center;
          }
      
          table,
          th,
          td {
              border: 1px solid #ccc;
              border-collapse: collapse;
          }
      
          caption {
              font-size: 18px;
              margin-bottom: 10px;
              font-weight: 700;
          }
      
          tr {
              height: 40px;
              cursor: pointer;
          }
      
          table tr:nth-child(1) {
              background-color: #ddd;
          }
      
          table tr:not(:first-child):hover {
              background-color: #eee;
          }
          </style>
      </head>
      
      <body>
          <h2>学生信息</h2>
          <p>将数据渲染到页面中...</p>
      
          <table>
              <caption>学生列表</caption>
              <tr>
                  <th>序号</th>
                  <th>姓名</th>
                  <th>年龄</th>
                  <th>性别</th>
                  <th>家乡</th>
              </tr>
              <script>
                  // 1.数据准备
                  let students = [
                      { name: '小明', age: 18, gender: '男', hometown: '河北省' },
                      { name: '小红', age: 19, gender: '女', hometown: '河南省' },
                      { name: '小刚', age: 17, gender: '男', hometown: '山西省' },
                      { name: '小丽', age: 18, gender: '女', hometown: '山东省' }
                  ]
      
                  // 2.开始渲染页面
                  for (let i = 0; i < students.length; i++) {
                      document.write(`
                      <tr>
                          <td>${i + 1}</td>
                          <td>${students[i].name}</td>
                          <td>${students[i].age}</td>
                          <td>${students[i].gender}</td>
                          <td>${students[i].hometown}</td>
                          </tr>
                      `)
                  }
              </script>
          </table>
      
      </body>
      
      </html>
      

10.4 内置对象

10.4.1 Math对象包含的方法
  • 1️⃣Math.random():生成0-1之间的随机小数(🔺包含0不包括1
    • 如何生成0-10的随机小数?
      • let num = Math.floor(Math.random() * (10 + 1))
        
    • 如何生成5-10的随机数?
      • let num = Math.floor((Math.random() * (5 + 1)) + 5
        
    • 如何生成N~M的随机数?
      • let num = Math.floor(Math.random() * (M - N + 1)) + N
        function getRandom (N, M) {
          // return Math.floor(Math.random() * (M - N + 1)) + N;
          return parseInt(Math.random() * (M - N + 1)) + N;
        }
        
    • 数组随机数:
      Math.floor(Math.random() * arr.length)
      
  • 2️⃣Math.ceil(数据):向上取整
    • 代码展示:
      console.log(Math.ceil(1.1))	// 2
      console.log(Math.ceil(1.01))	// 2
      
  • 3️⃣Math.floor(数据):向下取整
    • 代码展示:
      console.log(Math.floor(1.9))	// 1
      console.log(Math.floor(1.99))	// 1
      
  • 4️⃣Math.max(数据):找最大数
    • 代码展示:
      console.log(Math.max(0.1, 1, 65, 23, 88))  // 88
      
  • 5️⃣Math.min(数据):找最小数
    • 代码展示:
      console.log(Math.min(99, 65, 3, 0.1, -99))	// -99
      
  • 6️⃣pow:幂运算(了解)
  • 7️⃣Math.abs(数据):绝对值
    • 代码展示:
      console.log(Math.abs(-100))	// 100
      
  • 8️⃣Math.round(数据):四舍五入(取整数)
    • 代码展示:
      console.log(Math.round(2.45))	// 2
      console.log(Math.round(2.5))	// 3
      console.log(Math.round(-20.5))	// -20
      console.log(Math.round(-20.51))	// -21
      

贰、❗❗ Web APIS

  • Web API:是一套操作网页内容(DOM)与浏览器窗口(BOM)的对象
    • API:就是一些预定义好的方法,这些方法可以实现特定的功能,开发人员可以直接使用
    • Web API:浏览器提供了一套操作网页和浏览器的方法,通过这些方法可以轻松的操作元素和浏览器
  • 复杂数据类型const 声明:复杂数据类型 放在 里面,栈里面存放的地址指向堆里面存放的数据,变的只是堆里面存放的数据,存放数据的地址没有发生变化
  • 变量名 -> 栈地址-> 堆数据
  • const实际上指的并不是变量的值不得改动,
    其实说的是变量指向的那个内存空间中保存的数据不得改变
    简单数据类型是将值保存在栈中,所以用const声明简单数据类型时,值不得改变,相当于常量
    而复杂数据类型是将引用地址保存在栈中,具体的值保存在堆中
    那么用const声明复杂数据类型时,比如对象,数组时,只能保证的是这个地址是固定不变的
    堆中保存的数据是不是可变的,就无法保证了
    

一、❗❗ DOM(文档对象模型)

  • Document Object Model — 文档对象模型
  • 定义:是HTML文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以在从程序中对该结构进行访问,从而改变文档的结构,样式和内容。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将 web 页面和程序语言连接起来。进而操作网页的内容,实现各种功能和部分特效。

1.1 DOM树 和 DOM对象

1.1.1 DOM树
  • DOM树:一种树状结构,把页面标签按照树状结构排列好,结构更加清晰
    • 每个DOM对象中都有表示层级关系的属性,利用这些属性把所有的DOM对象联系在一起,就形成一个树状结构,称为DOM树
  • 作用:文档树直观的 体现了 标签与标签 之间 的 关系image-20220725201648559
1.1.2 DOM对象
  • **DOM对象:**浏览器根据htm标签自动生成的JS对象
    • 浏览器把网页内容翻译成一个个的对象,把 网页内容 的 特征 翻译成 对象 的属性
  • document对象:是DOM里提供的一个对象(DOM里面最大的对象
    • 它提供的属性和方法都是 用来访问操作 网页内容

1.2 获取DOM对象

  • 打印对象:打印元素的时候,以对象的形式展现
    console.dir(对象);
    
1.2.1 ❗❗ 根据CSS选择器来获取DOM元素
  • 1️⃣ 选择匹配的 第一个 元素
    • 语法
      document.querySelector('css选择器')
      
    • 代码展示:
      const li = document.querySelector('ul li')
      
    • 参数:小括号里面 包含 一个 或 多个 有效的css选择器 字符串(引号)
    • 返回值
      • css选择器 匹配的 第一个元素,一个 HTMLElement 对象
      • ⚠ 如果 没有匹配 到元素就是 null
      • ⚠ 注意:必须加引号
  • 2️⃣ 选择匹配的 多个 元素
    • 语法
      document.querySelectorAll('css选择器')
      
    • 代码展示:
      const lis = document.querySelectorAll('li') //NodeList[li, li, li]
      
    • 参数:小括号里面 包含 一个 或 多个 有效的CSS选择器 字符串
    • 返回值
      • CSS选择器匹配的 NodeList 对象集合
      • 如果页面 不存在 这个 元素,得到的就是一个 空的伪数组
      • 所有 匹配的 元素 放到 NodeList🟨伪数组🟨 里面 返回
      • 有长度,有索引
      • 没有push(),pop()等数组方法
      • 想要得到里面的每一个对象,则需要遍历获得
1.2.2 获取HTML、body、head、title
document.documentElement	--- 	html
document.body			--- 	body
document.head			--- 	head			
document.title			--- 	title
1.2.3 ❌其他获取元素的方式
  • 1️⃣根据 id 获取元素
    • document.getElementById('id名称')
      
    • 注意:
      • id名称不加 #
  • 2️⃣根据 标签 获取 一类 元素
    • document.getElementsByTagName('标签名称')
      
    • 注意:
      • getElementsByTagName
      • 返回值:伪数组
  • 3️⃣根据 类名 获取元素
    • document.getElementsByClassName('类名')
      
    • 注意:
      • 类名不加 .
      • getElementsByClassName
      • 返回值:伪数组

1.3 操作元素内容

1.3.1 对象.innerText 属性
  • 元素 文本内容 添加/更新 到 任意标签 位置
  • 显示 纯文本不解析标签
  • 见代码展示
1.3.2 对象.innerHTML 属性
  • 元素内容 添加/更新 到任意标签位置
    • 包括标签、文本、注释
  • 会解析标签,多标签建议使用模板字符串
  • ⚠ 既要保留原来内容又要添加新内容,采用 字符串拼接 的方式
    • innerHTML += '要添加的文本'
      
  • 见代码展示
    代码展示
<div class="box"> 天地不仁以万物为刍狗!!! </div>
<strong>
    const box = document.querySelector('.box') 
    // 对象.innerText 属性
    box.innerText = '扶我起来,我还能干!!!'
    box.innerText = '<strong>扶我起来,我还能干!!!</strong>'
  
    // 对象.innerHTML 属性
    box.innerHTML = '扶我起来,我还能干!!!'
    box.innerHTML = '<strong>扶我起来,我还能干!!!</strong>'
</strong>
image-20220725223214605
  • innerText 和 innerHTML 的区别
    • innerText
      • 只能 获取 元素文本,无法 获取 标签
      • ⚠ 在获取文本的时候,包含 子元素 的 文本
    • innerHTML
      • 可以 获取对象里面的所有 文本+标签
    • 代码展示:
      <body>
          <div>
              123
              <p>456
              <span>789</span>
              </p>
          </div>
      
          <script>
              console.log(document.querySelector('div').innerText);
              console.log(document.querySelector('div').innerHTML);
          </script>
      </body>
      
image-20220816081122736
1.3.3 获取表单元素文本
  • 语法: 元素.value
  • 获取 输入的字符长度元素.value.length
  • ⚠ 获取 button 的文本依然使用 innerHTML(button双标签)
  • 拓展:
    • 元素.value.trim() - 去除字符串 左右两侧 的空格

1.4 操作元素属性

1.4.1 操作 元素 属性
  • 语法元素.属性 = ‘值’
    • 代码展示:
      <img src="./images/1.webp" alt="">
      //随机数函数
      function getRandom(N, M) {
        return Math.floor(Math.random() * (M- N + 1)) + N
      }
      //获取图片对象
      //img在html中是标签,在js中是对象
      const pic = document.querySelector('img')
      // 修改对象的属性值
      pic.src = `./images/${getRandom(1, 6) }.webp`
      
1.4.2 控制 样式 属性
  • 1️⃣ 通过 style属性 操作css
    • 语法元素.style.样式属性 = ‘值’
      • 对于复杂的样式属性建议使用 小驼峰 命名法
      • 生成的是 行内样式表,权重很高,只有 !important 能做掉它
      • ⚠🔺 只写 属性
    • 代码展示:
      // 获取对象(元素)
      const box = document.querySelector('div')
      // 修改样式属性 对象.style.样式属性 = '值'
      box.style.width = '400px'
      box.style.height = '100px'
      box.style.backgroundColor = 'red'
      box.style['background-color'] = 'green'
      
  • 2️⃣ 通过 类名(className) 操作css
    • 语法:元素.className = ‘类名’
      • 注意:会覆盖前面的类名 新值换旧值
      • 想要原来的类名 -> 元素.className = ‘旧类名 新类名’
    • 代码展示:
      <style>
        div {
          width: 200px;
          height: 200px;
          background-color: pink;
        }
        .active {
          width: 300px;
          height: 300px;
          background-color: hotpink;
          margin-left: 100px;
        }
      </style>
      
      <body>
        <div class="one"></div>
        <script>
          // 1.获取元素
          // let box = document.querySelector('css选择器')
          let box = document.querySelector('div')
          // 2 给div添加类名 class 是个关键字,选用className替代它
          // 新值换旧值,会覆盖原来的类名
          box.className = 'active'
          // 用旧类名+新类名的形式覆盖原来的类名
          box.className = 'one active'
        </script>
      </body>
      
  • ❗3️⃣ 通过 classList 操作类 控制css
    • 语法
      • 追加 类:元素.classList.add(‘类名’)
      • 删除 类:元素.classList.remove(‘类名’)
      • 切换 类:元素.classList.toggle(‘类名’)
        • 如果有这个类名就是删掉,没有就追加
      • 替换 类:元素.classList.replace(‘旧类名’, ‘新类名’)
        • 两个参数,第一个是原来的类名,第二个参数是替换的类名
      • 是否包含指定的 类:元素.classList.contains(‘类名’)
        • 判断是否包含指定的类名,返回值是布尔值 true / false
    • ⚠ 注意:
      • 类名 不加 点,并且 是 字符串
      • 方法,注意加小括号
    • 代码展示:
      // 获取对象
      const box = document.querySelector('.one')
      
      // 追加类名
      box.classList.add('two')
      box.classList.add('three')
      
      // 删除类名
      box.classList.remove('three')
      
      // 切换类名
      // 如果有这个类名就是删除,没有就是追加
      box.classList.toggle('ab')
      box.classList.toggle('one')
      
      // 替换类名
      // 将 旧类名box 替换成 新类名box1
      box.classList.replace('box', 'box1')
      
      // 判断是否包含指定的类名
      console.log(box.classList.contains('box'))		// true
      
image-20220726101208459
  • classList 和 className区别
    • classList追加类名,将新类名追加到旧类名后面,不影响以前的类名
    • className覆盖类名,新类名 覆盖 旧类名,影响以前的类名
1.4.3❗❗ 操作 表单元素 属性
  • 语法
    • 获取元素.属性名
    • 设置元素.属性名 = 新值
  • 代码展示:获取表单里面的值
    const input = document.querySelector('.computer')
    console.log(input.value)
    input.value = '扶我起来,我还能干!!!'
    
  • ⚠ 注意:对象.innerHTML 只能获取 普通元素文本,获取 表单元素文本 需要使用 对象.value
    • 注意: 对象.value 获得的文本是 包含 首尾空白符
      • 想要获得 有效的文本 需要使用 trim() 方法[对象.value.trim()],删除首尾的空白符
    • ⚠注意:获取 button 的文本还是用 innerHTML
  • 表单属性中添加就有效果,移除就没有效果,一律使用 布尔值 表示,如果为 true 代表 添加 了该 属性 ,如果是 false 代表 移除属性
    • disabled(禁用)、checked(选中)
    • 除了 ’ 'false0nullundefinedNaN 其余的都是true,但是不建议写,建议写布尔值
    • 代码展示:
      <input type="checkbox" value="" name="">
      const input = document.querySelector('.computer')
      input.checked = true	// 让复选框选中
      input.checked = false	// 让复选框不选中
      input.disable = true	// 禁用吗? - 禁用(true)
      input.disable = false // 禁用吗? - 不禁用(false默认值)
      
1.4.4 ❗❗ 自定义属性
  • 属性
    • 标准属性:标签天生自带的属性,可以直接使用 点语法 操作
    • 自定义属性:
      • 在h5中推出了专门的 data- 自定义属性
      • 在标签上一律以 data- 开头(必须以 data- 开头)
      • 在DOM对象上一律以 dataset 对象方式获取
      • dataset 是一个 自定义属性集合包含 该标签内所有 自定义属性
      • 代码展示:
        <div data-id="1" data-spm="不知道">1</div>
        <div data-id="2">2</div>
        <div data-id="3">3</div>
        <div data-id="4">4</div>
        <div data-id="5">5</div>
        <script>
          // 获取元素
          const one = document.querySelector('div')
        	// one是一个HtmlElement对象
        	console.log(one)
        	// dataset是一个对象集合
        	console.log(one.dataset)
        	// 获取dataset对象里面的id属性
        	console.log(one.dataset.id)
        	// 获取dataset对象里面的spm属性
        	console.log(one.dataset.spm)
        </script>
        
      image-20220726160921554
  • ❌⛔ 拓展:
    • 获取自己 瞎定义的属性
    • 浏览器不会识别 瞎定义属性,并且它不会体现在DOM对象上
    • 语法:
      DOM对象.getAttribute(瞎定义属性名)
      

1.5 ❗❗ 定时器 - 间歇函数

  • 定时器 = setInterval() + setTimeout()
  • setInterval(函数, 间隔时间)(间歇函数):按照指定的周期(以毫秒计)来调用函数或计算表达式。方法会不停地调用函数,直到clearInterval()被调用或窗口关闭
    • 间歇函数可以根据时间自动重复执行某些代码
  • setTimeout(函数, 延迟时间)(延时函数):在指定的毫秒数后调用函数或计算表达式 (Timeout - 超出)
  • 定时器 里面的 第一个参数 是 回调函数
    • 将一个函数作为参数传递给另外一个函数,这个函数就是回调函数
1.5.1 开启定时器
  • 语法
    匿名函数:setInterval(函数, 间隔时间)		// Interval - 间隔,间隙
    具名函数:setInterval(函数名, 间隔时间)
    
  • 作用:每隔一段时间 回头调用函数(先隔段时间 ,再调用函数)
    • 间隔时间 单位 是 毫秒(ms),不用写
    • 不是立即调用函数,时间间隔 过后再去 调用函数
  • 间歇函数返回值
    • 表示 当前定时器 是 页面中 的 第几个 定时器,是一个 id数字数字型)(唯一的)
    • 一个 间歇函数 只有 一个 返回值,并且是唯一
  • 代码展示:
    // 匿名函数
    setInterval(() => {
      console.log('扶我起来,我还能干!!!')
    }, 1000)
    
    // 具名函数
    function fn() {
      console.log('扶我起来,我还能干!!!')
    }
    setInterval(fn, 1000)
    // fn() --- 执行这个函数,只执行一次 (fn()调用这个函数)
    // fn --- 每隔一段时间,回头去找fn这个函数(自动调用),再执行(fn是一个变量,代表这个函数)
    
    // 定时器的返回值,是数字型,是id
    // 声明一个变量,接收定时器的返回值
    let n = setInterval(() => {
      console.log(1)
    }, 1000)
    console.log(n)			// 1
    
    function fn() {
      console.log('扶我起来,我还能干!!!')
    }
    let m = setInterval(fn, 1000)
    console.log(m)			// 2
    
1.5.2 关闭定时器
  • 语法
    // 匿名函数
    let 变量名 = setInterval(函数, 时间间隔)
    // 具名函数
    let 变量名 = setInterval(函数名, 时间间隔)
    clearInterval(变量)
    
  • 代码展示:
    // 匿名函数
    let n = setInterval(() => {
      console.log(11)
    }, 1000)
    
    // 具名函数
    function fn() {
      console.log('扶我起来,我还能干!!!')
    }
    let m = setInterval(fn, 1000)
    
    // 关闭定时器
    clearInterval(n)
    clearInterval(m)
    

二、❗❗ DOM事件基础

2.1 事件监听(绑定)

  • 让程序检测是否有事件产生,一旦事件触发,就立即调用一个函数做出响应,也称为 绑定事件 / 注册事件
  • 事件监听三要素:
    • 事件源
    • 事件类型
    • 事件调用的函数(事件处理函数)
  • 语法
    元素对象.addEventListener('事件类型', 要执行的函数)
    
  • ⚠ 注意:事件类型 要加 引号
    • L2 注册的 事件 不会 出现 覆盖
    • L0 注册的事件会发生覆盖(后面的覆盖前面的)(同对象、同事件类型)
  • 代码展示:
    // 获取元素
    const btn = document.querySelector('button')
    // 事件监听-点击事件
    btn.addEventListener('click', () => {
      alert('扶我起来,我还能干!!!')
    })
    

2.2 事件类型

2.2.1 鼠标事件
  • 1️⃣ click - 鼠标点击
  • 2️⃣ mouseenter - 鼠标经过
  • 3️⃣ mouseleave - 鼠标离开
  • 4️⃣ mousemove - 鼠标移动
  • 5️⃣ dblclick - 鼠标左键双击
2.2.2 焦点事件
  • 1️⃣ focus - 获得焦点
  • 2️⃣ blur - 失去焦点
2.2.3 键盘事件
  • 1️⃣ keydown - 键盘按下触发
  • 2️⃣ keyup - 键盘抬起触发
  • 注意: 用鼠标粘贴内容不会触发
2.2.4 文本事件
  • 1️⃣ input - 用户输入事件
    • 获取用户 输入文本对象.value
    • 获取用户 输入文本长度对象.value.length
      • 注意:
        • 得到的 是 数字型
        • 包括 左右两侧 的 空格
    • 想要获得 有效文本和长度 (不包括首尾的空白符)
      • 有效文本: 对象.value.trim()
      • 有效长度: 对象.value.trim().length
      • trim() 方法:删除 字符串 首尾 空白符(空格、制表符、换行符等其他空白符)
      • 不会 改变 原始字符串
      • 不适用于null,undefined,Number类型
2.2.5 表单事件
  • 1️⃣ submit - 提交事件
  • 2️⃣ change - 失去焦点并且表单内容发生改变触发事件
  • 3️⃣ 重置表单: form.reset()
2.2.6 光标的坐标
  • 1️⃣ clientX 和 clientY
    • 光标距相对于 浏览器 可视化窗口 左上角 的位置
    • 鼠标在窗口中的位置
  • 2️⃣ pageX 和 pageY
    • 光标距离 文档流 左上角 的位置
    • 鼠标在页面中的坐标
    • 计算鼠标在某个盒子中的坐标:
      • 鼠标到盒子顶部的距离 = 鼠标到页面顶部的距离 - 盒子顶部到页面顶部的距离
      • 鼠标到盒子左侧的距离 = 鼠标到页面左侧的距离 - 盒子左侧到页面左侧的距离
    • image-20220814150651433
  • 3️⃣ offsetX 和 offsetY
    • 光标距离 DOM元素 左上角 的位置
    • 鼠标在标签中的位置
  • ⚠🔺 拓展:利用 js 调用 事件
    • 语法:元素.事件类型()

2.3 事件对象 - event

  • 也是个对象,里面有事件触发时相关的信息
2.3.1 获取事件对象
  • ⚠ 使用场景:
    • 可以判断用户按下哪个键
    • 可以判断鼠标点击了哪个元素,从而做相应的操作
  • 语法:
    • 事件绑定回调函数第一个参数 就是 事件对象
    • 一般命名为 event、ev、e
    • element.addEventListener('事件类型', function (e) {})
      
  • 在触发 DOM 上的某个事件时,会产生一个事件对象
  • event对象 包含与创建它的特定相关的和方法
2.3.2 事件对象常用属性
  • type获取 当前的 事件类型
  • clientX / clientY:获取 光标 相对于 浏览器可视化窗口 左上角 的位置
  • offsetX / offsetY:获取 光标 相对于 当前DOM元素 左上角 的位置
  • pageX / pageY : 光标距离 文档流 左上角 的位置
  • key
    • 用户 按下 键盘键的值
    • 现在不提倡使用keyCode
  • 代码展示:
    元素.addEventListener('click', function (e) {
      console.log(e.key)
      console.log(e.type)
    })
    

2.4 环境对象

  • 函数内部特殊的变量 this,代表当前函数运行时所处的环境
  • 每个函0数 里面 都有 this
  • 非严格模式
    • this指向函数的调用者(普通函数里面 this -> window)
    • 事件侦听里面,指向事件源
    • 箭头函数没有this(箭头函数不会自己创建this,它只会沿用自己所在这条作用域链的上层作用域的this)
    • 定时器里面this指向window

2.5 回调函数

  • 官方:如果将函数A作为参数传递给函数B时,我们称函数A为 回调函数
  • 把一个 函数 当作 参数 来 传递给 另外一个函数 的时候,这个函数就是 回调函数

三、❗❗ DOM事件进阶

3.1 事件流

3.1.1 事件流与两个阶段说明
  • 事件流 = 事件捕获 + 事件目标 + 事件冒泡
    • 事件流指的是:事件 完整执行过程 中的 流动路径
    • 过程:事件捕获 => 事件目标阶段 => 事件冒泡 整个完整的过程就是事件流
  • 两个阶段:
    • 捕获阶段:从父到子(从大到小)
    • 冒泡阶段:从子到父(从小到大)
    • 实际工作中都是使用 事件冒泡 为主
  • image-20220731230107629
3.1.2 ❌ 事件捕获(了解)
  • 概念:从DOM的 根元素 开始去执行对应的事件(从外到里)
  • 事件捕获需要写对应代码才能看见效果
    • 代码:
      DOM.addEventListener(事件类型, 事件处理函数[, 是否使用捕获机制 = false])
      
      • addEventListener第三个参数传入 true 代表是捕获阶段触发(很少使用)
      • 若传入false代表冒泡阶段触发,默认就是false
      • 若是用 L0(on事件类型) 事件监听,则只有冒泡阶段,没有捕获
3.1.3 事件冒泡
  • 从子到父(从小到大)
  • 概念:当一个元素触发事件后,会 依次 向上 调用 所有父级元素同名事件(同种事件类型)
  • 事件冒泡是默认存在的
  • 事件冒泡的必要性
    • 如果没有冒泡,给大盒子注册点击事件,点击的是里面的小盒子,会导致大盒子的点击无法执行
    • 事件委托(委托给祖先元素)
  • L2事件监听第三个参数是false,或者默认都是冒泡
  • 代码展示:
    const fa = document.querySelector('.father')
    const son = document.querySelector('.son')
    document.addEventListener('click', function () {
      alert('我是爷爷')
    })
    fa.addEventListener('click', function () {
      alert('我是爸爸')
    })
    son.addEventListener('click', function () {
      alert('我是儿子')
    })
    // 事件冒泡:从子到父
    // 弹出框的顺序依次是:儿子 -> 我是爸爸 -> 我是爷爷
    
3.1.4 阻止冒泡
  • 语法:
    事件对象.stopPropagation()		// 方法		停止传播		sp(快捷)
    e.stopPropagation()
    // 事件对象 - 回调函数的第一个参数
    
    • 此方法可以阻断事件流动传播 ,不光在冒泡阶段有效,捕获阶段也有效
  • 代码展示:
    const fa = document.querySelector('.father')
    const son = document.querySelector('.son')
    document.addEventListener('click', function () {
      alert('我是爷爷')
    })
    fa.addEventListener('click', function () {
      alert('我是爸爸')
    })
    son.addEventListener('click', function (e) {
      alert('我是儿子')
      // 阻止流动传播(阻止事件冒泡)
      // 在这一块卡住,不允许向上传播
      e.stopPropagation()
    })
    // 弹出框:我是儿子
    
  • 阻止元素默认行为:
    • 语法:
      e.preventDefault()		// 方法 阻止默认	pd(快捷)
      // 阻止 链接跳转
      // 阻止 表单提交(缺点:提交数据页面h)
      
    • 代码展示:
      <body>
        <form action="http://www.itcast.cn">
          <input type="submit" value="免费注册">
        </form>
        <a href="http://www.baidu.com">百度一下</a>
        <script>
          // 获取元素
          const a = document.querySelector('a')
          const form = document.querySelector('form')
          // 事件侦听-a-点击事件
          a.addEventListener('click', function (e) {
            // 阻止a的默认行为-页面跳转
            e.preventDefault()
          })
          // 事件侦听-form-提交事件
          form.addEventListener('submit', function (e) {
            // 阻止form的默认行为-表单的提交
            e.preventDefault()
          })
        </script>
      </body>
      
3.1.5 两种鼠标事件的区别
  • 注意:
    • mouseover 和 mouseout 会 有 冒泡效果
    • mouseenter 和 mouseleave 没有 冒泡效果(推荐)
3.1.6 解绑事件
  • 1️⃣ L0事件解绑(on方式)
    • 直接使用 null 覆盖就可以实现事件的解绑
    • 代码展示:
      btn.onclick = function () {
        alert('点击了')
      }
      // L0事件移除解绑
      btn.onclick = null
      
  • 2️⃣ L2 事件解绑
    • 语法:

      removeEventListener(事件类型, 函数名[, 获取捕获或冒泡阶段])
      
      • ⚠ 中括号包裹的参数可以省略
      • ⚠🔺 匿名函数 无法进行 事件解绑 操作
      • ⚠ 解绑的时候必须是 同一个函数(两个函数体一样 的 匿名函数 不是 同一个函数)
    • 代码展示:

      <script>
        // 获取元素
        const btn = document.querySelector('button')
      	// 声明函数
      	let fn = function (e) {
                  alert(`事件解绑语法:
                  元素.removeEventListener(事件类型, 函数名)
                  匿名函数 无法进行 事件解绑 操作
                  ${e.target.tagName}
                `)
              }
      	// 事件侦听-点击事件
      	btn.addEventListener('click', fn)
      	// 事件解绑
      	btn.removeEventListener('click', fn)
      </script>
      
3.1.7 两种注册事件的区别
  • 1️⃣ 传统on 注册(L0)
    • 同一个对象,后面注册的事件会 覆盖 前面注册的事件(同一个事件
    • 直接使用 null 覆盖就可以实现事件的解绑
    • 都是 冒泡阶段 执行的(只有冒泡没有捕获)
  • 2️⃣ 事件监听 注册(L2)
    • 语法:addEventListener(事件类型, 事件处理函数[ , 是否使用捕获 = false])
      • 既能捕获也能冒泡
      • 捕获 将第三个参数 改成 true
      • 冒泡不用写,默认就是冒泡(false)
    • 后面注册的事件 不会覆盖 前面注册的事件(同一个事件
    • 可以通过 第三个参数 去确定是在 冒泡阶段 或者 捕获阶段 执行的
    • 必须使用 removeEventListener(事件类型, 事件处理函数[ , 获取捕获或者冒泡阶段])
    • ⚠🔺 匿名函数无法解绑

3.2 事件委托

  • 优点:
    • 减少注册次数
    • 提高程序性能
    • ⚠ 为未来元素预备事件(添加节点)
  • 原理: 事件委托其实是利用 事件冒泡 的特点
    • 父元素 注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事件
  • 注意: 事件触发元素嵌套关系很复杂就不可以使用事件委托
  • 实现:
    • 获得 真正 触发事件 的 元素(对象):事件对象.target
    • 获得 真正 触发事件元素 的 标签名称:事件对象.target.tagName
  • 代码展示:
    <body>
      <ul>
          <li>第1个孩子</li>
          <li>第2个孩子</li>
          <li>第3个孩子</li>
          <li>第4个孩子</li>
          <li>第5个孩子</li>
          <p>我不需要变色</p>
      </ul>
      <script>
          // 1.点击每个小li,当前li文字变色
          // 按照事件委托的方式,委托给父级,事件写到父级身上
          // 获取元素
          const ul = document.querySelector('ul')
          // 事件绑定
          ul.addEventListener('click', function (e) {
              // e:事件对象
              // 得到一个事件对象
              // console.log(e)
              // 得到被点击的元素
              // console.log(e.target)
              // 得到被点击元素的标签名称
              // 得到的标签名称是 大写的 字符串
              // console.log(e.target.tagName)	// 'LI'
              // 判断点击的是不是li,如果是li文字就变颜色
              if (e.target.tagName === 'LI') {
                  e.target.style.color = 'red'
              }
          })
      </script>
    </body>
    

3.3 其他事件

3.3.1 页面加载事件
  • ⚠ JavaScript 写在body上面,必须 使用 load事件 或者 DOMContentLoaded事件
  • 1️⃣ load 事件
    • 等待页面 所有外部资源(外联CSS、外联JavaScript,图片……) 加载完毕 时,就回去执行回调函数
    • 事件名: load(等待)
    • 监听 整个页面 所有外部资源 加载完毕
      • ⚠ 给 window 添加 load 事件
      • 语法:
        window.addEventListener('load', function () {
          //	执行操作
        })
        
      • 代码展示:script标签在body标签上方
        <script>
          // 给 window 添加 页面加载事件(load)
          window.addEventListener('load', function () {
          // 获取元素
          const btn = document.querySelector('button')
          // 事件侦听-点击事件
          btn.addEventListener('click', function () {
            alert(`
               页面加载事件
               给 window 添加 load 事件
               window.addEventListener('load', function() {})
              `)
          })
        })
        </script>
        <body>
          <button>点击</button>
        </body>
        
      • ⚠ 注意:不光可以监听整个页面资源加载完毕,也可以针对某个资源绑定 load事件
  • 2️⃣ DOMContentLoaded 事件
    • 初始的HTML文档(DOM节点) 被完全加载和解析完成之后,DOMContentLoaded事件被触发,而无需等待外部资源加载
    • 事件名: DOMContentLoaded
    • 监听页面 DOM节点 加载完毕
      • ⚠ 给 document 添加 DOMContentLoaded 事件
      • 语法:
        document.addEventListener('DOMContentLoaded', function () {
          // 执行的操作
        })
        
      • 代码展示:
        document.addEventListener('DOMContentLoaded', function () {
          // 获取元素
          const btn = document.querySelector('button')
          // 事件侦听-点击事件
          btn.addEventListener('click', function () {
            alert(`
                页面加载事件
                给 document 添加 DOMContentLoaded 事件
                document.addEventListener('DOMContentLoaded', function() {})
              `)
          })
        })
        
3.3.2 元素滚动事件 - scroll
  • 滚动条 滚动的时候 触发(⚠ 页面 必须有 滚动条 才能 触发
    • 让 页面 具有 滑动效果 (不是瞬间到指定位置,而是缓慢滑动到指定位置)
      • /* 页面滑动 */
        html {
          /* 让滚动条丝滑的滑动 */
          /* 滚动-行为:平滑 */
          scroll-behavior: smooth;
        }
        
  • 让 html标签(页面最大的标签) 滚动
    • document.documentElement.scrollTop // html被卷去的高度
      window.pageYoffset		// 页面滚出去的高度(页面在竖轴的偏移量)
      document.documentElement.scrollTop === window.pageYoffset
      
  • 应用场景:固定导航栏、返回顶部
  • 事件名: scroll
  • 监听 整个页面 滚动
    • 语法:
      window.addEventListener('scroll', function () {
        // 执行的操作
      })
      
    • ⚠ 注意:
      • 给 window(常用) 或 document 添加 scroll 事件
      • 监听 某个元素的内部 滚动 直接给 某个元素 加即可
    • 代码展示:
  • 获取位置
    • scrollTop(被卷去的头部) 和 scrollLeft(被卷去的左侧) (属性)
      • ⚠🔺 读写属性(可以 读取 亦可以 赋值)
      • ⚠ 获取到的是 数字,赋值的时候 不带单位
      • 检测页面滚动的头部距离
        • document.documentElement.scrollTop = 数字
          
        • window.pageYoffset - 只读属性
          
      • 获取 被卷去 的大小
      • 获取 元素内容 往左、往上滚出去 看不到距离
      • ⚠ 得到的是:数字型 不带单位
      • 尽量写在 scroll事件 里面
      • 代码展示:
      <style>
        * {
          margin: 0;
          padding: 0;
          box-sizing: border-box;
        }
      
        body {
          height: 3000px;
        }
      
        div {
          display: none;
          margin: 100px auto;
          width: 470px;
          height: 150px;
          border: 1px solid #000;
          text-align: center;
          font-size: 20px;
          font-family: '隶书';
        }
      
        .active {
          display: block;
          position: fixed;
          top: 0;
          left: 50%;
          transform: translateX(-50%);
          margin-top: 0;
        }
      </style>
      
      <body>
        <div>
          世间的悲喜皆不如我所愿,但苦于乐皆是恩赐!!!
          世间的悲喜皆不如我所愿,但苦于乐皆是恩赐!!!
          世间的悲喜皆不如我所愿,但苦于乐皆是恩赐!!!
          世间的悲喜皆不如我所愿,但苦于乐皆是恩赐!!!
          世间的悲喜皆不如我所愿,但苦于乐皆是恩赐!!!
          世间的悲喜皆不如我所愿,但苦于乐皆是恩赐!!!
        </div>
        <script>
          // 事件侦听-页面滚动事件-window
          window.addEventListener('scroll', function () {
            // 获取html元素
            const html = document.documentElement
            // 获取div元素
            const div = document.querySelector('div')
            // console.log(html.scrollTop);		// 得到的是数字型
            // scrollTop >= 300显示div并固定在可视区域顶部,小于300隐藏
            if (html.scrollTop >= 300) {
              div.classList.add('active')
            } else {
              div.classList.remove('active')
            }
          })
        </script>
      </body>
      
    • 让页面 滚动到指定位置
      • 1️⃣ 属性赋值
        document.documentElement.scrollTop = 指定位置距离顶部的距离
        
      • 2️⃣ 方法
        window.scrollTo(x, y)
        
3.3.3 ❌ 页面尺寸事件 - resize(了解)
  • 窗口尺寸改变 的时候 触发事件
    • 事件类型: resize
    • 语法:
      window.addEventListener('resize', function () {
        // 执行的代码
      })
      
  • 检测屏幕宽度
    • 语法:
      window.addEventListener('resize', function () {
        let w = document.documentElement.clientWidth
        console.log(w)
      })
      
  • 获取元素宽高 (属性)
    • 获取元素的 可见部分 宽高(不包含border、margin、滚动条)
    • clientWidthclientHeight
    • 得到的是 数字型
    • image-20220802140421274

3.4 ❗❗ 元素的尺寸和位置

  • 1️⃣ 获取 宽高:(属性)
    • 获取元素 自身的宽高
      • 内容 + padding + border
    • offsetWidthoffsetHeight
    • 获取到的是 数值
    • ⚠ 获取的是 可视宽高,如果盒子是隐藏的,获取的结果是0
  • 2️⃣ 🔻 获取 位置:
    • ① 获取元素 距离自己 最近一级 定位 祖先元素左、上 距离
      • 带有 定位属性 的 祖先元素
      • 如果都没有,就以文档左上角为准
    • offsetLeftoffsetTop
      • 相对于 页面 来说
      • 只读属性
    • 获取的是可视宽高,若盒子隐藏,则获得的是0
    • ② ❌ 元素.getBoundingClientRect() (了解)
      • 返回元素的 大小 及其 相对于视口的位置
      • 相对于 视口
      • 代码展示:
        const div = document.querySelector('div')
        div.getBoundingClientRect()
        
    image-20220802172910019

总结

属性作用说明
scrollLeftscrollTop卷去头部左侧配合 页面滚动(scroll 事件) 来用,可读写
clientWidthclientHeight获得 元素宽度高度不包含border、margin、滚动条,用于js 获取元素大小 只读属性
offsetWidthoffsetHeight获得 元素宽度高度包含border、padding、滚动条等,只读属性
offsetLeftoffsetTop获取元素距离 自己定位父元素 的左、上距离获取 元素位置 的时候使用,只读属性
  • scroll系列 、 client系列 、 offset系列
    • scroll系列: 标签内部 内容 的大小,位置
      • scrollTop / scrollLeft:表示标签真实内容相对于标签的位置
      • ❌scrollWidth / scrollHeight:表示标签真实内容的大小(和标签本身的大小无关,是内容的宽高)
    • client系列: 标签 容纳范围(border里面) 的大小、位置
      • clientWidth / clientHeight:表示标签内容区域的大小
      • ❌clientTop / clientLeft:表示标签内容区域的位置(几乎不用,仅仅表示上边框的高度,左边框的宽度)
    • ✔🔻 offset系列: 标签本身 的大小、位置
      • offsetWidth / offsetHeight:包含content + padding + border
      • offsetTop / offsetLeft:最近一级带有定位属性祖先元素 的 相对位置(如果没有定位,那么就是相对于body)
  • 拓展:
    • 添加css让页面滚动平滑
      • html {
          scroll-behavior: smooth;
        }
        
    • if单分支语句拓展:
      • if (old) old.classList.remove('active')
        
      • old && old.classList.remove('active') - 逻辑与
        
      • old?.classList.remove('active') - 可选链
        
    • 属性选择器
      • document.querySelector('[data-name=new]')
        自定义属性 的 属性值 可以 省略 双引号(不推荐)
        

四、❗❗ 日期对象

  • 用来 表示时间 的 对象
  • 作用: 得到 当前系统时间
  • 日期对象:Date构造函数的实例,记录了一个时间信息

4.1 实例化

  • 实例化:有 new 关键字的都是实例化(见 JS 高级)
4.1.1 得到当前时间
  • 创建一个 时间对象 并 获取时间
    • 语法:
      const 常量名 = new Date()
      
    • 代码展示:
      const date = new Date()
      console.log(date)
      // Wed Aug 03 2022 20:37:52 GMT+0800 (中国标准时间)
      // 周三 八月 3号 年份 时间 
      
4.1.2 指定时间
  • 倒计时 的时候 使用
  • 语法:
    const 常量名 = new Date('指定的时间')
    
  • 参数:
    • 数字 : 月份是从 0 开始的
    • 字符串 : 月份是正常的
  • 代码展示:
    const date = new Date('2022-8-3 20:50:00')
    let h = date.getHours()
    console.log(h)	// number
    console.log(date)
    console.log(typeof date)	// object
    // Wed Aug 03 2022 20:50:00 GMT+0800 (中国标准时间)
    

4.2 日期对象方法

  • 语法作用说明
    对象.getFullYear()获得 年份获取 四位 年份
    对象.getMonth()获得 月份取值为 0 ~ 11
    对象.getDate()获取 月份中的 某一天不同月份取值不同
    对象.getDay()获取 星期取值为 0 ~ 6
    对象.getHours()获取 小时取值为 0 ~ 23
    对象.getMinutes()获取 分钟取值为 0 ~ 56
    对象.getSeconds()获取 取值为 0 ~ 59
    对象.getMilliseconds()获取 毫秒取值为 0~1000
  • 注意:
    • 周日是一周的开始 -> 周日 = 0
    • 当前月份 = 获取的月份 + 1
    • ⚠ 得到的都是 数字型

4.3 时间的另一种写法

  • 时间对象.toLocaleString() :年月日时分秒
  • 时间对象.toLocaleDateString() :年月日
  • 时间对象.toLocaleTimeString() :时分秒
  • 代码展示:
    // 获得当前系统时间
    const systemTime = new Date()
    // 从 获取的当前系统时间(systemTime)里找
    // 获取年份
    const year = systemTime.getFullYear()
    // 获得月份
    const month = systemTime.getMonth() + 1
    // 获取月份中的某一天
    const date = systemTime.getDate()
    // 获取星期
    const day = systemTime.getDay()
    // 获取小时
    const hours = systemTime.getHours()
    // 获取分钟
    const minutes = systemTime.getMinutes()
    // 获取秒
    const seconds = systemTime.getSeconds()
    console.log(systemTime);
    console.log(`${year}${month}${date} 日 周${day}  ${hours}${minutes}${seconds}`)
    // Wed Aug 03 2022 21:14:56 GMT+0800 (中国标准时间)
    // 2022 年 8 月 3 日 周3  21 时 14 分 56 秒
    
  • 格式化时间:
    <!DOCTYPE html>
      <html lang="en">
    
       <head>
       <meta charset="UTF-8">
       <meta http-equiv="X-UA-Compatible" content="IE=edge">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <title>Document</title>
    <style>
     * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    	}
    
    	div {
      	margin: 100px auto;
      	width: 600px;
      	height: 100px;
      	border: 5px solid #969696;
      	background-color: #d7d7d7;
      	color: hsl(338, 100%, 50%);
      	font-size: 44px;
      	font-weight: 700;
      	font-family: '华文隶书';
      	text-align: center;
      	line-height: 100px;
    	}
    </style>
    </head>
    
    <body>
      <div></div>
      <script>
          // 写法一:  
      	const div = document.querySelector('div')
              function getTime() {
                  const date = new Date()
                  let hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
                  let minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
                  let seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
                  return `当前时间:${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} 	${hours}:${minutes}:${seconds}`
              }
              
              div.innerHTML = getTime()
              setInterval(function () {
                   div.innerHTML = getTime()
              }, 1000)
              // 当前时间:2022-8-3 22:45:50
    
              // 写法二:自动补0
              /*
                  // 定时器外面再写一次的原因:定时器隔1s再去执行,用外面的填补页面空白
                  div.innerHTML = date.toLocaleString()
                  // div.innerHTML = date.toLocaleDateString()
                  // div.innerHTML = date.toLocaleTimeString()
                  setInterval(function () {
                      const date = new Date()
                      div.innerHTML = date.toLocaleString()	 // 2022/8/3 23:00:00
                      // div.innerHTML = date.toLocaleDateString()    // 2022/8/3
                      // div.innerHTML = date.toLocaleTimeString()    // 22:48:20
                  }, 1000)
              */
      </script>
    </body>
    </html>
    

4.3 时间戳

  • 使用场景:倒计时
  • 时间戳: 是指1970年01月01日00时00分00秒起 至现在毫秒数
  • 注意:
    • 时间戳唯一的
    • ⚠ 中国 在 东8区
      const date = +new Date('1970-01-01 00:00:00') / 1000 / 60 / 60
      console.log(date)	// -8
      
  • ⚠🔻 算法
    • 将来的时间戳 - 当前的时间戳 = 剩余时间毫秒数
    • 剩余时间毫秒数 转换为 剩余时间的 日时分秒 就是 倒计时
    • 展示:
      将来时间戳 2000ms - 现在时间戳 1000ms = 1000ms
      1000ms 转换时分秒就是 0小时0分1秒
      
  • 三种获取时间戳的方法:
    • 1️⃣ 使用 getTime() 方法
      • 语法:
        const date = new Date()
        console.log(date.getTime())	// 1659539589145 毫秒数
        // new Date().get.Time()
        拓展:
        时间对象.getTime() 和 时间对象.valueOf() 的到的结果一样
        console.log(date.getTime() === date.valueOf())	// true
        
      • 注意:
        • 必须 先 实例化
        • ⚠ 可以返回 指定时间的时间戳
    • 2️⃣ ✔简写 +new Date()
      • 语法:
        console.log(+new Date())  // 1659539732765 毫秒数
        
      • 注意:
        • + -> 正号 (隐式转换)
        • ⚠ 可以返回 指定时间的时间戳
          • 代码展示:
            conlose.log(+new Date('2022-10-1 07:30:00'))
            // 1664580600000 -- 指定时间的时间戳
            
    • 3️⃣ 使用 Date.now()
      • 语法:
        console.log(Date.now())  // 1659540040487 毫秒数
        
      • 注意:
        • 没有 实例化
        • ⚠ 只能得到 当前的 时间戳
  • 时间转换公式
    • 通过 时间戳 得到是 毫秒,需要转换为秒在计算
    • 转换公式:
      • days: d = parseInt(总秒数 / 60 / 60 / 24)
      • hours: h = parseInt(总秒数 / 60 / 60 % 24)
      • minutes: m = parseInt(总秒数 / 60 % 60)
      • seconds: s = parseInt(总秒数 % 60)
  • 倒计时函数:
    const element = document.qurySelector('css选择器')
    function getCountTime(time) {
      // 得到当前的时间戳(毫秒)
      const now = +new Date()
      // 得到未来时间时间戳(毫秒)
      const last = +new Date(time)
      // 得到剩余的时间戳(毫秒) 并转换为 秒
      const count = (last - now) / 1000
      // 将 剩余秒数 -> 天、时、分、秒
      let day = parseInt(count / 60 / 60 / 24)
      let hours = parseInt(count / 60 /60 % 24)
      // 补0
      hours = hours < 10 ? '0' + hours : hours
      let minutes = parseInt(count / 60 % 60)
      // 补0
      minutes = minutes < 10 ? '0' + minutes : minutes
      let seconds = parseInt(count % 60)
      // 补0
      seconds = seconds < 10 ? '0' + seconds : seconds
      return `${day} 天 - ${hours}:${minutes}:${seconds}`
    }
    
    function getRemainingTime(element, time) {
      // 先执行一次:定时器过1s再去执行,会有1s的显示空白时间,让它限制性,填补空白,再让后面的覆盖
      element.innerHTML = getCountTime(time)
      setInterval(function () {
          element.innerHTML = getCountTime(time)
          }, 1000)
    }
    
    getRemainingTime(div, '2022-10-1 00:00:00')
    

五、❗❗ 节点操作

  • 浏览器 使用 对象记录 网页内容
    • 浏览器把网页内容翻译成一个个的对象,把 网页内容 的 特征 翻译成 对象 的 属性
    • 这个对象就称为 DOM对象
    • 网页内容的特征:
      • 标签属性
      • 标签内容
      • 标签上下级
  • 网页内容 、对象
    • 网页内容: 标签、文本、注释
    • DOM对象:标签(元素)节点、文本节点、注释节点
    • 网页内容 和 DOM对象 一 一 对应
  • DOM树
    • 每个DOM对象中都有表示层级关系的属性,这些属性把所有DOM对象联系在一起,形成一个树状结构,称为DOM树
    • DOM树 === 网页

5.1 DOM节点

  • DOM节点: DOM树 里面 每一个内容 都称之为 节点
  • 节点类型:
    • 1️⃣ ❗✔元素节点:
      • 所有的 标签
      • html根节点
    • 2️⃣ 属性节点:
      • 所有的属性
    • 3️⃣ 文本节点:
      • 所有的文本
  • image-20220725201648559

5.2 查找节点 - 属性

  • 有效返回值 是一个 对象
  • 无效返回值 - null
5.2.1 父节点
  • 1️⃣ parentNode属性
    • 语法:
      子元素.parentNode
      
    • 返回值:
      • DOM对象
      • 最近一级 的父节点(亲爸爸),找不到 返回 null
    • 代码展示:
      <div class="yeye">
          <div class="dad">
              <div class="baby">x</div>
          </div>
      </div>
      
      <script>
          const baby = document.querySelector('.baby')
          console.dir(bady)		// div.bady -> DOM对象
          console.dir(baby.parentNode)	// div.dad -> DOM对象
          console.dir(baby.parentNode.parentNode)	  // div.yeye -> DOM对象
      </script>
      
    • 关闭广告:
      <!DOCTYPE html>
      <html lang="en">
      
      <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
          .box {
            position: relative;
            width: 1000px;
            height: 200px;
            background-color: pink;
            margin: 100px auto;
            text-align: center;
            font-size: 50px;
            line-height: 200px;
            font-weight: 700;
          }
      
          .box1 {
            position: absolute;
            right: 20px;
            top: 10px;
            width: 20px;
            height: 20px;
            background-color: skyblue;
            text-align: center;
            line-height: 20px;
            font-size: 16px;
            cursor: pointer;
          }
        </style>
      </head>
      
      <body>
        <div class="box">
          我是广告
          <div class="box1">X</div>
        </div>
        <div class="box">
          我是广告
          <div class="box1">X</div>
        </div>
        <div class="box">
          我是广告
          <div class="box1">X</div>
        </div>
      
        <script>
          // const smallBox = document.querySelectorAll('.box1')
          /* for (let i = 0; i < smallBox.length; i++) {
            smallBox[i].addEventListener('click', function () {
              this.parentNode.style.display = 'none'
            })
          } */
      
          // 事件委托
          document.body.addEventListener('click', function (e) {
            if (e.target.className === 'box1') {
              e.target.parentNode.style.display = 'none'
            }
          })
        </script>
      </body>
      
      </html>
      
5.2.2 子节点
  • 1️⃣ ❌childNodes 属性
    • 语法:
      父元素.childNodes
      
    • 返回值: 获得 所有子节点、包括文本节点(空格、行换)、注释节点等
  • 2️⃣ ⚠🔻 children 属性
    • 语法:
      父元素.children
      
    • ⚠ 返回值: 伪数组 (要想得到里面的每一个节点还是要遍历
    • 注意:
      • 仅获得 所有 元素节点(标签)
      • 只选亲儿子,只不过是把亲儿子里面包含的所有节点(元素、文本、注释…)拿过来
    • 代码展示:
      <ul>
         <li>
              1
              <p>6</p>
              <span>7</span>
          </li>
          <li>2</li>
          <li>3</li>
          <li>4</li>
          <li>5</li>
      </ul>
      
      <script>
        // 获取子节点
        // 语法:父元素.children
        // 返回值:伪数组
        // 仅 获得 所有 元素节点(标签)
        console.log(document.querySelector('ul').children);
      	// 得到的是一个伪数组
      </script>
      
image-20220804225759139
5.2.3 兄弟节点
  • 1️⃣ 下一个 兄弟节点
    • nextElementSibling 属性
    • 语法:
      兄弟元素.nextElementSibling
      
    • 返回值:
      • 有下一个兄弟节点,得到的就是下一个元素
      • 没有 就是 null
  • 2️⃣ 上一个 兄弟节点
    • previousElementSibling 属性
    • 语法:
      兄弟元素.previousElementSibling
      
    • 返回值:
      • 有上一个兄弟节点,得到就是上一个元素
      • 没有 就是 null
  • 代码展示:
    <ul>
      <li>
          1
          <p>6</p>
          <span>7</span>
      </li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
    </ul>
    
    <script>
      // 上一个兄弟节点
      // 语法:兄弟元素.previousElementSibling
      // 下一个兄弟节点
      // 语法:兄弟元素.nextElementSibling
      console.log(document.querySelector('ul li:nth-child(2)').nextElementSibling)
    </script>
    
    image-20220804232438001

5.3 增加节点

  • 创建 追加
5.3.1 创建节点
  • 语法:
    document.createElement('标签名')		// 文档.创建元素
    
    • 创建的节点是一个正常的DOM对象
    • ⚠ 注意:
      document.createElement()  --  创建的是空标签
      
5.3.2 追加节点
  • 1️⃣ 插入到 父元素最后一个 子元素
    • 语法:
      父元素.appendChild(要插入的元素)	// 追加孩子
      
    • 注意: 做为 父元素 里面最后一个 子元素
    • 代码展示:⬇
  • 2️⃣ 插入到 父元素某个子元素前面
    • 语法:
      父元素.insertBefore(要插入的元素, 在哪个元素前面)	// 插入在…之前
      
    • 注意: 插入到 父元素 里面指定位置
    • 代码展示:⬇
  • 注意: appendChildinsertBefore 如果插入的是页面上 已经存在 的标签,会有 剪切 效果(将已经存在的元素 从 原位置 剪切到 新位置)
  • 代码展示:
    <style>
        div,
        li {
          font-size: 20px;
          text-align: center;
          line-height: 50px;
        }
    
        li:first-child {
          width: 150px;
          height: 50px;
          background-color: #b8f0e8;
        }
    
        li:last-child {
          width: 150px;
          height: 50px;
          background-color: #a6a6db;
        }
    
        div {
          width: 150px;
          height: 50px;
          background-color: #c0bfbf;
        }
    </style>
    
    <body>
      <ul>
        <li>我是老大</li>
      </ul>
    
      <script>
        // 增加节点(节点 -> 元素节点)
        //  1.创建节点
        //    语法:document.createElement('标签名称')
        //  2.插入节点
        //    (1).作为父元素里面的最后一个子元素
        //        语法:父元素.appendChild(要插入的元素)
        //    (2).插入到父元素里面指定位置(插入到父元素里面某个子元素的前面)
        //        语法:父元素.insertBefore(要插入的元素, 在那个子元素前面)
    
        // 1.创建节点
        const li = document.createElement('li')
        li.innerHTML = '我是老二'
        // 2.插入节点
        //    2.1获取父元素
        const ul = document.querySelector('ul')
        //    2.2作为父元素里面的最后一个子元素
        ul.appendChild(li)
    
        // 1.创建节点
        const div = document.createElement('div')
        div.innerHTML = '我是老大的大哥'
        // 2.插入节点
        //    2.1获取父元素
        const body = document.body
        //    2.2插入到父元素指定位置(插入到父元素里面指定元素前面)
        body.insertBefore(div, ul)
        // 将创建的节点始终插入到父元素的最前面
        /*
          body.children  // 包含body下所有的(亲)子节点伪数组
        	body.insertBefore(div, body.children[0])
        */
      </script>
    </body>
    
    image-20220805002046014
5.3.3 克隆节点
  • 特殊情况 的 新增节点
  • 应用场景:轮播图
  • 步骤:
    • 1️⃣ 复制 一个 原有节点
    • 2️⃣ 把 复制的节点 放入到 指定元素内部
  • 语法:
    元素.cloneNode(布尔值)
    
    • clondNode会克隆出一个跟原标签一样的标签(原标签上面有什么,克隆后的标签上面就有什么)(是两个元素,克隆成功后前后两个元素没有任何关系)
    • 参数:
      • true - 深克隆: 克隆时 包含 后代节点 一起克隆 (节点 -> 文本节点、注释节点等所有的节点)
      • false - 浅克隆: 克隆时 不包含 后代节点、
      • 默认值false
    • 代码展示:
      <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
      </ul>
      
      <script>
          const ul = document.querySelector('ul')
          // const newLi = ul.children[0].cloneNode(true)
          // newLi.innerHTML = 'newLi'
          // ul.appendChild(newLi)
          ul.insertBefore(ul.children[0].cloneNode(true), ul.children[11])
      </script>
      

5.4 删除节点

  • 在 JavaScript 原生DOM操作中,要 删除元素 ⚠ 必须 通过 父元素 删除
  • 语法:
    父元素.removeChild(要删除的元素)
    
  • 注意:
    • 如果 不存在 父子关系 则 删除 不成功
    • 删除节点 和 隐藏节点(display: none;)有区别
      • 删除节点:从DOM中删除节点
      • 隐藏节点:只是在页面上不显示,DOM节点依然存在
  • 补充:
    • 语法: 自杀式z
      删除的元素.remove()
      
  • 拓展:
    • 替换节点:
    • 语法:
      parentNode.replaceChild(newChild, oldChild);
      
    • 方法用指定的节点替换当前节点的一个子节点,并返回被替换掉的节点
  • 重绘 和 回流
    • 重绘: 由于节点(元素)样式的改变并不会影响它在文档流中的位置和文档布局时,则是重绘
    • 回流: 元素的尺寸、结构、布局等发生变化时,浏览器就会重新渲染部分或全部文档的过程称为回流
    • 重绘不一定一起回流,但回流一定会引起重绘
    • 简单理解,影响到了布局,就会有回流

六、❌ M端事件

  • 常见的触屏事件(touch)
  • 触屏 touch 事件说明
    touchstart手指 触摸 到一个DOM元素时触发
    touchmove手指在一个DOM元素上 滑动 时触发
    touchend手指从一个DOM元素上 移开 时触发

七、❗ JS插件

  • 熟悉官网,了解这个插件可以完成什么需求 https://www.swiper.com.cn/
  • 看在线演示,找到符合自己需求的demo https://www.swiper.com.cn/demo/index.html
  • 查看基本使用流程 https://www.swiper.com.cn/usage/index.html
  • 查看APi文档,去配置自己的插件 https://www.swiper.com.cn/api/index.html
  • 注意: 多个swiper同时使用的时候, 类名需要注意区分
  • 使用步骤:
    • 引入资源
      • css文件
      • js文件
    • 导入代码
      • 复制html结构
      • 复制css样式
      • 复制js行为

八、❗❗ window对象

window(JS中的顶级对象) > BOM(浏览器对象模型) > DOM(页面文档对象模型)

8.1 BOM(浏览器对象模型)

  • BOM(Browser Object Model)- 浏览器对象模型
    • 由一些列相关的对象构成,并且每个对象都提供了很多方法和属性
    • 浏览器的内容被翻译成了对象
  • image-20220807205819018
  • window 对象是一个 全局对象,也可以说是 JavaScript 中的 顶级对象
  • 像document、alert()、console.log()这些都是window的属性,基本BOM的属性和方法都是window的
  • ⚠ 所有通过 var 定义在 全局作用域 中的 变量函数 都会变成 window对象属性方法
  • ⚠ window对象下的属性和方法调用的时候可以 省略window
  • DOM 和 BOM 区别:
    • image-20220912145005712

8.2 定时器 - 延时函数

  • 定时器 = 间歇函数(setInterval()) + 延时函数(setTimeout())
  • 让代码 延迟 执行的函数 - setTimeout()
  • 语法:
    setTimeout(回调函数, 等待的毫秒数)
    
  • 清除延时函数:
    let timerId = serTimeout(回调函数, 等待的毫秒数)
    clearTimeout(timerId)
    
  • 注意:
    • setTimeout 仅仅 只执行 一次 ,平时省略 window
    • 延时函数需要等待,所以后面的代码先执行
    • 每一次调用延时器都会 产生一个 新的 延时器
  • 间歇函数 和 延时函数 的区别:
    • 间歇函数:每隔一段时间就执行一次,除非手动清除
    • 延时函数:执行一次

8.3 JS执行机制

  • JS代码 从上到下 执行
  • 单线程: 同一时间只能做一件事
    • 所有的任务需要排队,前一个任务结束,才会执行后一个任务
8.3.1 同步 与 异步
  • 1️⃣ 同步
    • 前一个任务结束后再执行后一个任务,程序的执行顺序任务的排列顺序一致的
    • 同步任务: 都在 主线程 执行栈 上执行
  • 2️⃣ 异步
    • 如果执行一个任务需要花费一定的时间,在执行这个任务的同时可以去执行别的任务
    • 耗时 的都是 异步
    • JS的 异步 是通过 回调函数 实现的
    • 异步任务的三种类型
      • 普通事件(click、mouseenter、mouseleave、……)
      • 资源加载
      • 定时器 (间歇函数(setInterval) + 延时函数(setTimeout))
    • 异步任务 添加到 任务队列 (消息队列)中
  • 同步异步本质 区别:
    • 一条流水线上的 各个流程 执行顺序不同
  • 3️⃣ 执行机制:
    • ① 先执行 任务栈 中的 同步任务
    • 异步任务 添加到 任务队列 里面
      • 异步任务 进行 排序(根据每个异步任务所消耗的时间 )
    • ③ 一旦 执行栈 里面的 所有 同步任务 执行完毕系统 就会 按次序 读取 任务队列 中的 异步任务,于是 被读取异步任务 结束 等待状态进入 执行栈,开始执行。
    • image-20220808142927967
8.3.2 事件循环 - event loop
  • image-20220808144521013
  • 由于 主线程 不断的 重复 获得任务、执行任务、再获取任务、再执行,所以这种机制被称为 事件循环(enevt loop)
  • 事件循环: js执行代码时,会把同步任务添加到主线程执行栈中执行,把满足条件的异步任务推到任务队列排队等候执行,事件循环是一种轮询机制,当执行栈中的所有同步任务执行完毕之后,系统就会依次读取任务队列中的异步任务,异步任务结束等待状态,按照次序添加到执行栈中执行。

8.4 location 对象

  • location数据类型对象,它 拆分保存URL地址各个 组成 部分
  • 常用 属性 和 方法:
    • 1️⃣ ✔🔺 href: 属性 获取 完整的URL地址,对其 赋值时 用于 地址的跳转
      • const btn = document.querySelector('button');
        btn.addEventListener('click', function () {
            location.href = 'https://www.baidu.com';
        });
        
      • 可以后退
    • 2️⃣ search: 属性 获取地址中 携带的参数,符号 ? 后面部分
      • console.log(location.search); 	// 字符串
        
    • 3️⃣ hash: 属性 获取地址中的 哈希值,符号 # 后面部分
      • console.log(location.hash);		// 字符串
        
    • 4️⃣ reload(是否使用缓存): 方法 用来 刷新 当前 新页面,传入参数 true 时表示 强制刷新,默认false使用缓存刷新
      • const btn = document.querySelector('.reload');
        btn.addEventListener('click', function () {
          // F5 -> 刷新
          //location.reload();
          // F5+Ctrl -> 强制刷新  
          location.reload(true);
        });
        
    • 5️⃣ replace(): 方法 页面跳转(覆盖旧地址)
      • const btn = document.querySelector('button');
        btn.addEventListener('click', function () {
            location.replace('https://www.baidu.com');
        });
        
    • href属性replace()方法 实现页面跳转的区别:
      • href属性: 保留 原地址具有回退功能
      • replace()方法: 覆盖 原地址没有回退功能

8.5 navigator 对象

  • navigator数据类型对象,该对象记录了 浏览器 自身的 相关信息
  • 常用 属性 和 方法:
    • 浏览器相关信息:navigator.userAgent
    • 通过 userAgent 检测 浏览器版本平台
      // 检测userAgent(浏览器信息)
      !(function () {
        const userAgent = navigator.userAgent;
        // 验证是否为Android或iPhone
        const android = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/);
        const iphone = userAgent.match(/(iPhone\sOS)\s([\d_]+)/);
        // 如果是Android或iPhone,则跳转至移动站点
        if (android || iphone) {
          location.href = 'http://m.itcast.cn';
        }
      })();
      

8.6 history 对象

  • histroy数据类型对象,主要管理历史记录,该对象与浏览器地址栏的操作相对应。
  • 常用属性和方法:
    • back(): 可以 后退 功能
    • forward(): 前进 功能
    • go(参数): 前进 后退 功能
      • 参数:
        • 1: 前进 一个页面 (back())
        • 0: 刷新页面(使用缓存刷新) (reload())
        • -1: 后退 一个页面 (forward())
    • 代码展示:
      <button>后退</button>
      <button>前进</button>
      <script>
          // 获取元素
          const back = document.querySelector('button');
          const forward = back.nextElementSibling;
          // 事件侦听-点击事件
          back.addEventListener('click', function () {
          // 前进一步
          history.go(1);
          });
          forward.addEventListener('click', function () {
          // 后退一步
          history.go(-1);
          });
      </script>
      

九、❗❗ 本地存储

  • 数据存储 在 用户 浏览器 中(硬盘)
  • 设置、读取方便、甚至 页面刷新 不会丢失 数据
  • 容量较大、sessionStprangelocalStorage 约5M
  • 为什么要将数据存储到本地存储里?
    • 数据持久化(数据不丢失)

9.1 本地存储分类

9.1.1 localStorage
  • 作用: 可以 将 数据 永久存储本地(用户电脑),除非手动清除,否则关闭页面 也会 存在
  • 生命周期: 什么时候失效,什么时候死掉
  • 特性:
    • 可以多窗口(页面)共享同一浏览器可以共享)(不能跨域(同一个域名)使用)
    • 键值对 的形式 存储使用
  • ⚠🔻 语法:
    • 1️⃣ 存储/修改 数据:
      localStorage.setItem(key, value)		
      // 设置每个小项,key和value要加引号,key和value可以是变量
      
      • 这个键就是 修改没有 就是 添加
      • 代码展示:
        // 本地存储 - localStorage
        // 存储数据 - localStorage.setItem(key, value);
        // 要加引号
        localStorage.setItem('uname', '邵秋华');
        
        image-20220809085436994
    • 2️⃣ 获取 数据:
      localStorage.getItem(key)			// 获取里面的项,key必须加引号
      
      • 返回值:
        • 有这个key,就返回对应的值
        • 没有这个key,返回 null
      • 代码展示:
        // 获取数据 - localStorage.getItem(key)
        // 要加引号
        console.log(localStorage.getItem('uname'));	// 邵秋华
        
    • 3️⃣ 删除 某项数据:
      localStorage.removeItem(key)		// 移除里面的项, key必须加引号
      
      • 代码展示:
        // 删除本地存储
        localStorage.removeItem('uname');
        
    • 4️⃣ 清空 数据:
      localStorage.clear()
      
      • 慎用
      • 清空全部数据
  • ⚠⚠ 注意:
    • ⚠ 所有的 必须加 引号
    • 有这个键就是修改,没有就是添加
    • ⚠🔺 本地存储 只能存储 字符串 类型的数据
    • 得到的值也是字符串型
    • 如果value写的是数值型,存的时候会转换成字符型
    • 代码展示:
      const arr = [1, 2, 3, 4];
      arr.forEach((item, index) => {
        localStorage.setItem(`id:${index}`, item);
        console.log(localStorage.getItem(`id:${index}`));	// 1 2 3 4(字符串)
        console.log(typeof (localStorage.getItem(`id:${index}`)));// string
      });
      
9.1.2 sessionStprange
  • 特性:
    • 生命周期关闭浏览器窗口
    • 同一个窗口(页面)下 数据可以共享
    • 键值对 的形式 使用
    • 用法跟localStorage基本相同
  • localStoragesessionStorage 的区别
    • 他们的 作用 相同,但是 存储方式 不同,因此应用场景也不同
    • localStorage 的数据可以 长期存储关闭浏览器 数据不会消失,除非 手动清除
    • sessionStorage 的数据时是 临时存储页面被关闭,存储在sessionStorage里的 数据 会被 清除

9.2 存储复杂数据类型

  • 本地存储 只能存储 字符串,不能存储 复杂数据类型
  • JSON:
    • 属性和值都有引号,而且是双引号
    • 一种字符串格式的名称
    • 把 数组/对象 转换为结构为 ”数组/对象“ 的字符串
    • 只能存:数字、字符串、对项
    • 不能存null、undefined、函数
    • ⚠ JSON.parse(转换数据):要转换的数据不是JSON格式的字符串image-20220815085625050
  • 存储复杂数据类型步骤:
    • 1️⃣ 将 复杂数据类型JSON字符串
      • 语法:
        JSON.stringify(复杂数据类型)
        
      • 代码展示:
        // 本地存储只能存储字符串,不能存储复杂数据类型
        // 如果要存储复杂数据类型,需要将复杂数据类型转换成 JSON 字符串
        // 语法:JSON.stringify(复杂数据类型);
        let obj = {
          uname: '邵秋华',
          age: 22,
          gender: '男',
        };
        
        localStorage.setItem('obj', JSON.stringify(obj));
        
        image-20220809093054731
    • 2️⃣ 将 JSON字符串复杂数据类型
      • 语法:
        JSON.parse(JSON字符串)
        
      • 代码展示:
        console.log(JSON.parse(localStorage.getItem('obj')));
        
        image-20220809094516421
  • 存:
    • 复杂数据类型 -> JSON.stringify() -> JSON字符串 -> 存到本地存储中
  • 取:
    • 从本地存储中取 -> JSON字符串 -> JSON.parse() -> 复杂数据类型

十、❗ 正则表达式

  • 正则表达式(Reular Expression):用于 匹配 🔺字符串🔺 中 字符组合模式
    • JavaScript 中,正则表达式 也是 对象(object )
    • ⚠🔺 注意: 只能对 字符串 进行匹配
  • 正则表达式的作用
    • 1️⃣ 表单验证(匹配
    • 2️⃣ 过滤敏感词汇(替换
    • 3️⃣ 字符串中提取我们想要的部分(提取 ->-爬虫)

10.1 正则表达式的使用

  • 1️⃣ 定义规则:
    • 语法:
      const regObj = /表达式/	// 正则表达式不改变使用
      
      const regObj = new RegExp('表达式')	// 正则表达式变化使用
      
    • 注意:
      • // 正则表达式 的 字面量
      • // 中间写什么,就查找什么
      • ⚠🔺 // 中间 不要乱加 空格
      • 只要涉及到正则表达式不要乱加空格,最好用vs格式化
  • 2️⃣ ✔检测查找是否匹配:
    • 语法:
      • test() :用来 查看 正则表达式指定的字符串 是否匹配
      • regObj.test(被检测的字符串)
        
    • 返回值:
      • 匹配true
      • 不匹配false
      • 规则在前面,被检测的就是用户输入的内容
    • 注意:
  • 代码展示:
    // 正则表达式
    // 正则表达式使用
    // 1)定义规则
    //    语法:const 变量名(regObj) = /表达式/;
    //    注意:正则表达式的字面量中间 不要乱加空格
    //    字面量中间些什么就匹配什么(不要乱加空格)
    // 2)是否匹配
    //    语法:regObj(字面量).test(被检测的字符串);
    	const reg = /前端/;
    	const str = '我在学习前端,希望学完高薪就业!!!';
    	console.log(reg.test(str));		// true
    
    // 注意
    	const reg = / 前端 /;
    	const str = '我在学习前端,希望学完高薪就业!!!';
    	console.log(reg.test(str));		// false
    
    // 注意
    	console.log(//.test('哈'));		// true
    	console.log(//.test('哈哈'));	// true
    	console.log(//.test('二哈'));	// true
    
  • 3️⃣ ⭕检索符合规则的字符串:
    • 语法:
      • exec():在一个 指定字符串 中执行一个 搜索匹配
      • regObj.exec(被检测字符串)
        
    • 返回值:
      • 匹配数组
      • 不匹配null
  • 代码展示:
    const reg = /前端/;
    const str = '我在学习前端,希望学完高薪就业!!!';
    console.log(reg.exec(str));	
    
    image-20220809181458176
  • 正则表达式检测查找 test()方法 和 exec()方法 有什么区别?
    • text(): 用于判断是否有符合规则的字符串,返回的是一个布尔值,找到 返回 true没找到 返回 false
    • exec(): 用于检索(查找)符合规格的字符串,找到 返回 数组没找到null

10.2 ❗ 元字符

  • 字符
    • 普通字符
      • 大多数的字符仅能够描述它们本身(字母数字)
      • 普通字符 只能够 匹配 字符串中 与 它们 相同的字符
    • 元字符
      • 是一些 具有 特殊含义 的 字符
      • 优点: 极大提高了 灵活性 和 强大的匹配功能
  • ⚠🔻 边界符、量词、字符类 组合使用
  • 1️⃣ 边界符
    • 表示位置,开头和结尾,必须用什么开头,用什么结尾
    • 用来提示字符所处的位置
      • 边界符说明
        ^表示匹配 行首 的文本(以谁开始
        $表示匹配 行尾 的文本(以谁结束
      • 注意:
        • ^ $ 在一起,表示 必须是 精确匹配
      • 代码展示:
        console.log(//.test('哈'));		// true	// 字符串的内容 和 规则相等
        console.log(//.test('哈哈'));	// true
        console.log(//.test('二哈'));	// true
        
        console.log(/^哈/.test('哈'));	// true
        console.log(/^哈/.test('哈哈'));	// true
        console.log(/^哈/.test('二哈'));	// flase
        
        console.log(/^哈$/.test('哈'));	   // true
        console.log(/^哈$/.test('哈哈'));  // false -- 精确匹配(字符串的内容、长度必须和规则相等)
        console.log(/^哈$/.test('二哈'));  // flase
        
  • 2️⃣ 量词
    • 表示重复次数
    • 设定 某个模式出现 次数
    • 量词说明
      *****重复 零次多次 >= 0
      +重复 一次多次 >=1
      ?重复 零次一次
      {n}重复 n次
      {n,}重复 n次更多次 >= n
      {n,m}重复 n 到 m 次 n <= 次数 <= m
      • ⚠🔺注意:
        • 🔺n,m🔻 之间 🔺没有空格🔻
        • 离量词 最近的(量词的左边) 重复,别的不重复
  • 3️⃣ 字符类
    • [] - 匹配字符集合
      • 被检测的数据 只要能和 规则 匹配到 任意🔺一个🔻字符 就是 true,否则就是false
      • 代码展示:
        后面的字符串只要包含abc中任意一个字符,都返回true
        console.log(/[abc]/.test('andy'));  // true
        console.log(/[abc]/.test('baby'));  // true
        console.log(/[abc]/.test('cry'));   // true
        console.log(/[abc]/.test('die'));   // false
        
      • 精确匹配: 被检测的数据 🔺只能🔻 和 规则 匹配 🔺一个🔻 字符(n选1),要想多个匹配须和量词配合使用
        console.log(/^[abc]$/.test('a'));	  // true
        console.log(/^[abc]$/.test('b'));	  // true
        console.log(/^[abc]$/.test('c'));	  // true
        console.log(/^[abc]$/.test('ab'));	// false
        console.log(/^[abc]{1,}$/.test('abc'));	// true
        
    • - 连字符
      • 使用连字符 - 表示一个 范围
      • [a-z] : 表示 a~z 26个英文字母都可以
      • [a-zA-Z] : 表示大小写都可以
      • [0-9] : 表示 0~9 都可以
      • [\u4e00-\u9fa5] 匹配汉字
        
      • 代码展示:
        /^[1-9][0-9]{4,}$/	// 第一个数字:1~9;从第二位开始:0~9;可以重复>=4
        
    • ^ - 取反符号
      • [] 加上 ^ 取反符号
      • [^a-z] :匹配除了小写字母以外的字符
      • 注意: 写到 [] 里面
    • . 匹配 除了换行符之外的任何单位
    • 预定义类:某些常见模式的简写方法
      • 预定义说明
        \d匹配 0-9之间任一数字,相当于[0-9]
        \D匹配所有 0-9以外字符,相当于[ ^0-9]
        \w匹配任意的 字母、数字和下划线,相当于[A-Za-z0-9_]
        \W除所有字母、数字和下划线以外的字符,相当于[ ^A-Za-z0-9_]
        \s匹配空格(包括换行符、制表符、空格符等),相等于[\t\r\n\v\f]
        \S匹配非空格的字符,相当于[ ^\t\r\n\v\f]
        • 日期:^\d{4}-\d{1,2}-\d{1,2}$
          
    • () 使用小括号将字符包成一个整体
    • |
  • 特殊符号写到 [] 里的最后面

10.3 修饰符

  • 修饰符 约束 正则表达式的某细节 行为 ,如是否区分大小写、是否支持多行匹配
  • 语法:
    /表达式/修饰符
    
    • i: (ignore)正则匹配时 不区分 大小写
    • g: (global)匹配 所有 满足正则表达式结果 (全局匹配)
    • m: 执行多行匹配
    • 代码展示:⬇
  • replace - 替换
    • 语法:
      字符串.replace(/正则表达式/, '替换文本')
      
    • 返回值: 替换好的字符串
    • 代码展示:⬇
    • 替换多个:
      字符串.replace(/正则表达式/g, '替换文本')
      
      • 代码展示:⬇
    • 替换多个 并且 不区分大小写:
      字符串.replace(/正则表达式/ig, '替换文本')
      字符串.replace(/正则表达式/gi, '替换文本')
      
      • ⚠🔺 g i 不区分 前后
      • 代码展示:⬇
    • 替换多个 并且 不区分大小写:(用正则表达式里面的
      字符串.replace(/正则表达式|正则表达式/, '替换文本')
      
      • ⚠🔺 或(|) 两侧 不要加 空格
      • 如果没有小括号,就是将正则表达式分成多份
      • 代码展示:⬇
    • 代码展示:
      // 修饰符:约束正则表达式的细节行为
      // 语法: /正则表达式/修饰符
      // i(不区分大小写) + g(匹配所有满足正则表达式的结果)
      // i
      console.log(/^java$/.test('JAVA'));   // false
      console.log(/^java$/i.test('JAVA'));  // true
      console.log(/^java$/i.test('JavA'));  // true
      
      // 替换 - replace
      // 语法:字符串.replace(/正则表达式/, '替换文本')
      const str = 'java是一门编程语言,学完JAVA工资很高';
      
      // 替换一个
      const re1 = str.replace(/java/, '前端');
      console.log(re1);		// '前端是一门编程语言,学完JAVA工资很高'
      
      // 替换多个 - g
      const re2 = str.replace(/java/ig, '前端');
      console.log(re2);		// '前端是一门编程语言,学完前端工资很高'
      
      // 替换多个 - 或(|) (正则表达式里的或)(|两侧不要加空格)
      const re3 = str.replace(/java|JAVA/g, '前端');
      console.log(re3);		// '前端是一门编程语言,学完前端工资很高'
      
  • 拓展:
    • change - 事件
      • 当鼠标离开表单,并且表单值发生变化触发
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值