javascript的简介
###javascript 是什么
java: 类似 java 计算机编程语言
script: 脚本
类似 java 计算机编程语言的脚本语言,缩写为 js
## java 和 javascript 的区别
- 静态编译: 将 java 的程序编译生成为一个.class 文件
- 编译型语言(java、c)和解释型语言(js)
- java 静态编译,js 作为脚本动态编译
- java 是强类型语言,js 是弱类型语言
- 蹭热度 JavaScript 蹭 java 的热度
## javascript 的作用
提供了一个和 html 进行动态交互的功能
什么是变量?如何声明变量
变量就是存放数据的一个容器 (盒子)
变量所保存的数据本质是存储在计算机的内存中的! 内存是通过硬件内存条所产生一块虚拟空间!通常称为内存空间!
声明变量
在js中 通过 var 关键字 就可以声明一个变量
声明变量语法
var a
声明变量的同时赋值,变量的初始化
var num = 100
同时声明多个变量 多个变量之间用逗号分隔
var a, b, c, d
var 关键字可以重复声明相同的变量
js在ES6之前,变量的声明只能通过 var关键字进行声明
js在ES6之后可以采用 let 或者 const 关键字进行变量的声明
let 语法规则
let a
a = 200
变量的初始化
let A = 200
同时声明多个变量
let b, c, d
ncaught SyntaxError: Identifier 'a' has already been declared
a这个变量你怎么重复声明呢,之前不是声明过了吗????
let关键字不能在同一作用域重复声明相同的变量
const 语法规则
const关键字是用于声明 常量的!
常量:就表示该变量中保存的数据不允许更改!
Uncaught SyntaxError: Missing initializer in const declaration
const num = 200
利用赋值运算符 重新修改num的值
num = 300 // Uncaught TypeError: Assignment to constant variable.
const声明的常量变量,是不允许修改的!
const同样在同一作用域下不允许声明相同的变量
变量数据的使用和修改
<!-- src属性是引入外部的js文件 -->
<!-- type引入文件的类型, 默认是指向 text/JavaScript -->
<script type="text/JavaScript">
// 变量数据的使用和修改
// 声明一个变量
var num
// 对num变量进行赋值
num = 200
// 使用num变量中的数据
console.log(num)
console.log(num + 100) // 1.首先读取num的值 200 2. 进行运算 200 + 100 3.输出 300
// 修改变量的值
// 在js中修改一个变量的值必须通过 '=' 赋值运算符
// num = 450
num + 300
console.log(num) // 200
标识符的命名规则
变量(标识符)
标识符就是表示该环境下,作用域的一些数据!
标识符能表示 变量 函数 类 方法 对象 .....
标识符的命名大部分是由程序员自定义命名的
自定义命名的时候,应该遵循标识符的命名规范
js中的标识符命名规范:
1.标识符只能由字母 数字 下划线 以及$符号组成
2.标识符不能以数字进行开头
3.标识符严格区分大小写
4.不能采用关键字或者保留字进行标识符的定义
-- 关键字:js语法规范中,提前规定好了一些单词!并且js也赋予其特殊的含有!这些单词称为关键字! 比如 if else break for var let const....
-- 保留字:js语法规范中,以前收录了一些单词!但目前这些单词未真正的投入使用,测试阶段!并没有任何的含义! 这些单词称为保留字
注意:以上4条就是js标识符命名规范的硬性准则!
5.标识符如果由多个单词构成!应遵循 '小驼峰命名法' : blackcolor ==> blackColor
6.标识符的命名应该遵循 '见名知义' : name ,age ,sex 不要取这些名字: a1 b2 abc ......
数据类型
数据类型是什么?js 中对不同种类数据的一个类型分类
什么是数据?数据就是对现实事物的一种抽象表达!
程序:利用程序代码去解决实际的问题!处理数据!
对于事物的不同表达,数据的类型是有划分的!在 js 中数据是明确具备类型的!
mdn 为数据类型一共定义了 8 种:
7 种原始类型
- undefined
- Boolean
- Number
- String
- BigInt
- Symbol
- null
- 注意:在 ES6 之前只有 undefined、Boolean 、 Number 、 String、null
- ES6 后新增加了两种数据类型, BigInt 、 Symbol(符号)
最后一种类型是:
- Object (对象类型,在 js 中使用构造函数所创建的对象!都属于 Object 对象类型)
数据按照参数的传递方式,可以分为 `值传递类型` 和 `引用传递类型`
## 值类型
- Boolean 布尔型
- Number 数字型
- String 字符串
- BigInt 长整数
## 引用类型
- Object 对象类型
- Symbol 符号类型
## undefined 未定义
undefined 是一个单独的类型,用于给已经定义的变量设置的初始值
## null 空引用
null 值的是空引用,是 js 的一个原始数据类型,用来指代引用类型数据的空值
## 值类型和引用类型数据的区别
值类型:变量中直接存贮值本身
引用类型:变量中存储的是引用地址,而值是存在引用地址所指向的内存中的某个对应位置
值类型
Number 数值类型,不再进一步的去区分int或者float 100 3.14
Stirng 使用单引号'' 或者 "" 或者 `` 包裹起来的字符串 字符串类型,js中没有字符类型
Boolean 布尔类型,表示事物的两种状态, 真(true) 和 假(false)
BigInt 长整型,该类型是用于表示,超出基本number能表示的数值范围! bigint通常用于描述巨大的值
引用类型
Object对象类型
Symbol符号类型
null 类型 特殊的一种引用类型
值类型与引用类型的存储方式
值类型 、 引用类型
这两者的区别体现在哪里?
体现在内存中存储的方式不同!
var num = 100
console.log(num) // 100
num = 300
console.log(num) // 300
var num = 100
var num2 = num
num = 300
console.log(num2) // 100
创建一个花括号对象,{}
花括号对象中具备,属性和方法,以键值对的形式进行存储表示!
‘=’赋值运算符,运算顺序是从右往左!
将赋值号右边表达式的值赋值给左边的变量
var person = {
name: '张三',
age: 18,
}
var p2 = person
// 访问 p2 对象
console.log(p2) // {name:张三,age:18}
// 修改p2的age属性
p2.age = 20
console.log(p2) // {name:张三,age:20}
console.log(person) // {name:张三,age:20}
json对象
json对象,花括号对象
json对象的创建利用{}进行创建
json对象中数据的存储采用键值对的方式, key:value ,其中key的数据类型必须是字符串,value可以是任何的合法数据类型!
json对象中多个属性值使用逗号分隔
大多数时候,js允许省略key的引号或者双引号,省略的前提是属性名的命名符合标识符的命名规则
// Object类型的数据都可以采用以下方式进行操作对象
var person = {
name: '张三',
age: 18,
sayHello: function () {
console.log('你好!')
},
'black@color': 'red'
}
console.log(person)
1. 属性值的读取操作
- 方式一:通过.语法 语法规则: 对象.属性 可以把.理解为语文上'的'
- 方式二:通过[属性名]
获取person对象的name值 点语法
console.log(person.name)
console.log(person.age)
console.log(person.sayHello)
console.log(person.black@color)
读取对象中不存在的属性
console.log(person.xxx) // undefined 读取对象中不存在的属性时其返回数据为 undefined
[] 语法规则 对象[属性名]
console.log(person['black@color']) //
2.添加属性 利用赋值运算符,为一个不存在的属性进行赋值!就是在为该对象添加一个新的属性并且赋值!
console.log(person.xxxx)
person.xxxx = '我是xxxx属性值'
console.log(person.xxxx)
console.log(person)
person['xxxx'] = '我是xxx数据'
console.log(person)
3.修改属性值 利用赋值运算符
person.age = 300
console.log(person)
4.对象类型中不允许存在两个同名属性!后一个会覆盖前面的属性值!
注意:以上这些操作,适用于任何的Obeject数据类型!
undefined
undefined类型
该类型的值有且仅有一个 undefined
undefined用于表示未赋值变量的状态!
null类型
null类型,是一种特殊的引用类型,
null类型的值有且只有一个 null
null是一个特殊的Object对象类型 typeof检测的返回值是 Object
null类型通常用于指向一个不存在的对象空间! 表示为'空'
切断变量的引用链!释放空间,也可以使用null
检测数据类型
js中的数据类型有8种
原始数据类型(7) 和 对象类型(1)
口诀: 四基两空双一
四基: Number、String、 Boolean 、 BigInt
两空: undefined 、 null
双一: 一个符号 Symbol 一个对象 Object
对于js种数据类型的多样化,如何快速的检测其数据的类型!
利用js所提供一个运算符 typeof 类型检测
语法: typeof 数据
typeof 运算后的数据属性什么数据类型!
typeof 的返回值是字符串类型!
var res1 = typeof 100
var res2 = typeof 'hello world!'
var res3 = typeof {}
var res4 = typeof true
// res1 res2 res3 res4 所存储的数据是什么类型?字符串、
console.log(typeof res1,typeof res2,typeof res3 , typeof res4)
json对象的序列化和反序列化
json格式的数据本质上一段字符串!该书写格式是于js中的json对象书写是一致的!
json对象的序列化和反序列化
序列化:将一个合法的json对象,转换为一段标准的json格式的数据!
反序列化:将一段标准的json格式的数据,字符串转化为一个合法的json对象!
// 序列化 利用js提供的JSON对象上的方法进行操作 JSON.StringIfy
// console.log(obj,typeof obj)
// 对obj对象进行序列化操作
// JSON.stringify(arg) arg:json对象
var res = JSON.stringify(obj)
console.log(res, typeof res)
// 反序列化 利用js提供的JSON对象上的方法进行操作 JSON.parse()
// JSON.parse(arg) arg ==> json数据
var newobj = JSON.parse(res)
console.log(newobj, typeof newobj)
console.log(newobj.name, newobj.age)
newobj.age = 20
json数据的作用是方便数据的传输!json数据是一种轻量的js数据格式!该数据不仅仅用于前端!后端!也会使用!嵌入式!
json对象的数据格式 JSON数据
json(JavaScript Object Notation, JS 对象简谱) : 轻量化js数据结构
为什么使用json对象,作用是什么?json 对象主要用于存储数据,有着简洁的数据结构,正由于这样的特点,json 对象常用于网络信息传输中,传递数据
数据类型的转换
数据的类型转换:将某个数据的类型通过某种方式转换为另一种数据类型! 比如: number ==》 string
数据转换通过方式不同可以分为:强制转换、隐式转换
强制转换:人为的通过手段去改变一个数据的类型
隐式转换:没有人为的参与,是程序解析自动进行转换
强制转换:
Number(x)函数 该函数可以将其他的数据类型强制转换为Number类型的数据
NaN表示该类型无法找到对应的Number值与之匹配!Symbol类型无法被转换为Number
实际的开发中,常常将 string Boolean 转换为 Number
补充:除了Number()函数可以强制转换其他数据为Number类型外,还有两种手段
全局函数: parseInt() parseFloat
parseInt() 将其他数据类型转换为number的整数值
String() 该函数是将其他类型强制转换为字符串类型
Boolean() 该函数是将其他类型强制转换为布尔类型
js中的假值,假值就是通过强制转换或者隐式转换该数据为布尔类型后,其结果为false的数据称为假值!
js中的假值: false 、 0 、 -0 、 +0 、 null 、 undefined 、 ''
运算符
运算符的作用,利用各种运算符,对已有数据进行运算然后得到新的数据!
js中的运算符分类:
- 算术运算符
- 赋值运算符
- 比较运算符
- 逻辑运算符
- 三元运算符
- 单目运算符
运算符
算术运算符: + 、 - 、 * 、 / 、%(模运算,取余)、**(幂运算)
算数运算符主要用于两个number数据的计算!
如果算术运算符一侧数据类型不为number则js将进行隐式转换!转换为numnber类型然后进行运算!
// +法运算
//注意:如果+号的一侧数据类型为字符串类型,则+号就自动变成字符的拼接运算
console.log(5 + 5)
console.log(100 + 3.14)
console.log(-100 + 785)
console.log(5 + true) // 5 + true 等价于 5 + Number(true)
console.log(100 + {}) // 100 + '[object Object]' 100[object Object]
console.log(100 + null)
console.log(100 + undefined) // 100 + Number(undefined) ==> 100 + NaN = NaN
//-法运算
console.log(100 - 20)
console.log(100 - 3.14)
console.log(-20 - 30)
console.log(20 - {})
console.log(20 - null)
console.log(20 - undefined)
//*法运算
console.log(5 * 5)
console.log(5 * 3.14)
console.log(5 * -7)
console.log(5 * {})
console.log(5 * null)
// /法运算,是数学意义上的除法运算!
console.log(6 / 2)
console.log(6 / 3)
console.log(7 / 3)
// % 模运算,取余运算
//5 % 3 ==》 商1 余2 结果:2
console.log(100 % 10)
console.log(7 % 3)
//** 幂运算
console.log(5 ** 3)
console.log(2.1 * 3)
console.log(0.1 + 0.2)
赋值运算符
赋值运算符
'=' 强调赋值运算符,不是数学意义上的等于符号!它是赋值运算!
运算流程: 将赋值运算符的右侧表达式的结果,赋值给左边的变量! 从右往左
let num = 30 // 将30赋值给左侧的 num变量
注意:赋值运算符可以改变变量或者对象属性的具体值!
表达式:表达式是js语句的最小单位!
表达式是可以通过计算得到一个确定的值!类似的式子就可以称为表达式!
比如: 5+5 算术表达式 、300 > 200 比较表达式 、 Number('123') 函数表达式 、 200 常量表达 式 、 num 变量表达式!
复合赋值运算符
复合赋值运算符:该运算符是 赋值运算符 与 算数运算符的结合书写!
注意:复合赋值运算符也具备赋值运算的功能!
+= 、 -= 、 /= 、 %= 、 **= 、*=
let num = 30
// num = num + 30
num += 30 // 等价于 num = num + 30
num -= 20
num /= 2
num *= 5
num %= 10
num **= 7
比较运算符
比较运算符:用于对两个数据进行数据的比较,其比较结果为布尔值!true 或 false
js中的比较运算符: > 、< 、 >= 、<=、 ==、 ===、 != 、!==
>
console.log(100 > 1) // true
console.log(100 > 200) // false
console.log(100 > '300') // 隐式转换 等价于 100 > Number('300')
console.log('a' > 'b') // 字符的ASCII码 a==>97 b==>98
<
console.log(100 < 30)
console.log(100 < 50 - 20)
>=
console.log(100 >= 100)
<=
console.log(100 <= 200 - 100)
== 等于,注意这才是js的等于!
双等于,特点是,进行比较时如果两侧的数据类型不一致!首先进行隐式转换!
console.log(100 == 100)
console.log(100 == '100') // 隐式转换 100 == Number('100') ==> 100 == 100 ==> true
=== 全等于,三等,
全等的特点是,只会比较数据的值,如果数据的类型都不同!直接返回false!
1. 先检测两边的类型是否一致 如果不一致则直接返回 false
2. 进行值的比较,查看是否相等
console.log(100 === 100)
console.log(100 === '100')
console.log(100 === 100)
console.log({} === {}) //注意:引用数据类型进行比较时,比较的是地址值!
!= 不等于
不等于,特点,如果两侧数据类型不同还是会进行隐式转换!
console.log(100 != 100) false
console.log(100 != '100') false
!== 不全等 特点,不会进行隐式转换,只要!==的两边数据类型不同直接返回! true
console.log(100 !== 100) // false
console.log(100 !== '100') // true
建议:以后如果遇到需要比较两个值是否相等的情况下,请采用三等!尽量不要采用双等!
逻辑运算符
逻辑运算符:用于对两个逻辑值的运算!
js中的逻辑运算符: &&(与) ||(或) !(非,取反)
逻辑运算表达式的返回结果是什么类型?结果:可以是任何数据类型!
&& 与运算
运算语法: 表达式1 && 表达式2 如果&&运算两侧的数据类型不是布尔类型,则先进行隐式转换! Boolean()
与运算口诀: 全真为真,一假即假
console.log(false && false) // false
console.log(true && false) // false
console.log(true && true) // true
console.log(false && true) // false
console.log(false && false && true) // false
console.log(100 > 200 && 200 < 300) // false && true ==> false
console.log(100 && true) // Boolean(100) && true true && true
console.log(false && '')
console.log(100 && 200) // Boolean(100) && Boolean(200) true && true ==> true 200
注意:js中的逻辑与和逻辑或都是属于短路与,短路或!
短路与:
特点在运算时,从左往右计算,如果碰到其中一个表达式的值为,false,那么后续的表达式将不再进行计算!并且返回当前表达式的原始值作为整个与运算的结果!
如果从左往右计算,都没有遇到false,那么将最后一个表达式的原始值作为整个与运算的结果!
var num = 100
console.log(100 < 30 && (num += 10))
console.log(num) // 1. 110 2. 100
console.log(0 && true) //Boolean(0) ==》 false 0 原始值
console.log(0 && true)
console.log('' && true)
console.log(null && true)
console.log(undefined && true)
console.log(true && true && true && '')
逻辑或(短路或)
运算语法: 表达式1 || 表达式2 如果||运算两侧的数据类型不是布尔类型,则先进行隐式转换! Boolean()
或运算口诀: 全假为假,一真即真
console.log(false || false) // false
console.log(false || true) // true
console.log(true || true) // true
console.log(true || false) //true
短路或的运算特点
特点在运算时,从左往右计算,如果碰到其中一个表达式的值为,true,那么后续的表达式将不再进行计算!并且返回当前表达式的原始值作为整个或运算的结果!
如果从左往右计算,都没有遇到true,那么将最后一个表达式的原始值作为整个或运算的结果!
console.log(100 || false) // 100
console.log({} || false) // {}
console.log([] || false) // []
console.log(true || false) // true
console.log(false || false || false || [])
!取反运算 非运算
口诀: 真变假,假变真
console.log(!false)
console.log(!true)
自增自减运算
自增、自减
++ 、 --
自增运算: 前自增、后自增 , 运算符都是 ++ 只是++的位置不同
自减运算: 前自减、后自减 , 运算符都是 -- 只是--的位置不同
自增,自减运算
运算规则: 将变量自身的值取出来+1或-1,然后重新赋值给变量!
let num = 50
num = num + 1
console.log(num)
前自增和后自增的区别:
前自增,是先将数据进行+1,然后再参与其他的运算
后自增,是先利用原始数据参与其他的运算,然后再进行+1操作
let num = 50
console.log(++num + 50) // 101
// console.log(num++ + 50) // 100
console.log(num)
// 注意:表达式一旦计算完毕!值已经确定!则表达式的结果不能更改!
条件(三目)运算符
三目:操作数,为3
* 双目
! 单目
语法规则: 表达式?结果1:结果2
运算流程: 计算表达式结果,如果表达式为真,则将结果1的数据进行返回,否则返回结果2的数据
let res = 100 < 50 ? 100 : 200
let num = false ? 10 + 1 : 20 + 1
console.log(num)
单目运算符
js中的单目运算符
! 、 typeof ...
单目运算的操作数只有一个!
逗号运算和括号运算
// 逗号运算符,始终将最后一个,号表达式的值最后整个逗号表达式的运算结果
let a, b, c
let res = (1, 2, 3, 4)
console.log(res)
// 小括号()
// js中利用()可以改变运算符的优先级!以及将一些表达式看作为一个整体进行计算!
console.log((5 + 5) * 8)
流程控制语句
js的代码如果没有人为的干预,那么js的执行顺序为从上往下,顺序执行!
作用:流程控制语句后,可以对js的代码执行顺序进行干预,完成更复杂的程序逻辑!
js中的三大流程控制结构:
顺序结构 选择结构 循环结构
顺序结构: 整体代码的解析执行是按照从上往下!的规律进行执行!也是最基础的控制结构
选择结构: 为代码的执行提供可能的路径!影响代码的走向!
循环结构: 重复的执行某一段代码!
选择结构
选择结构
js中的选择结构控制语句:
if 单分支
if...else 双分支
if...else...if 多分支
switch 条件多分支
if 语句
语法:
if (表达式) {
代码段
}
执行流程,判断if后表达式的值!如果为true,则执行{}中的代码段!false则不执行{}中的代码段,直接回到程序的主路径
let age = 17
if (age >= 18) {
console.log('恭喜你成年了!')
}
console.log('end___')
if...else 语句 双分支
语法:
if (表达式) {
代码段1
} else {
代码段2
}
执行流程,判断if后表达式的值!如果为true,则执行代码段1的内容,如果为false,则执行代码段2中的内容!,最终回到主路径!
let age = 18
if (age >= 18) {
console.log('恭喜成年,可以上网!')
} else {
console.log('抱歉,未成年!滚')
}
console.log('end——————')
//练习1: 随机从键盘上输入一个数值,判读奇偶!
js的输入语句,浏览器提供的一个api 全局函数
let res = prompt('请输入数据:')
console.log(res)
let num = prompt('请输入数字:')
if (num % 2 == 0) {
console.log('偶数')
} else {
console.log('奇数')
}
//练习2: 随机输入一个年份,判断平润年
能被4整除但不能被100整除或者能被400整除 闰年
let year = prompt('输入一个年份:')
if ((year % 4 === 0 && year % 100 != 0) || year % 400 === 0) {
console.log('闰年')
} else {
console.log('平年')
}
多分支语句
js多分支语句,if...else的嵌套
// 双分支,是两条路径选择!
// 多分支,是多条路径进行选择!
// 多分支的本质就是利用if和else嵌套!
// 语法:
// if(表达式){
// 路径1
// }else if(表达式){
// 路径2
// } else {
// 路径3
// }
let num = prompt('请输入一个成绩:')
if (num >= 90) {
console.log('优秀')
} else if (num >= 80) {
cosole.log('良好')
} else {
console.log('一般')
}
console.log('end——————')
条件分支语句
// js的条件分支语句 switch语句
// 语法:
// switch (表达式) {
// case '值':
// 语句块
// case '值':
// 语句块
// case '值':
// 语句块
// case '值':
// 语句块
// case '值':
// 语句块
// case '值':
// 语句块
// ....
// default:
// 不满足其他case分支时,进行default!
// }
let res = prompt('请输入一个字符:')
switch (res) {
case 'A':
console.log('我是A')
break
case 'B':
console.log('我是B')
break
case 'C':
console.log('我是C')
break
case 'D':
console.log('我是D')
break
default:
console.log('没有任何case匹配')
}
console.log('end——————')
// switch执行流程,计算表达式的值,然后与{}中case进行匹配!匹配一旦成功则从对应的case段落开始执行,一直到{}的末尾!
// switch在执行的过程中如果没有被break语句进行打断则一直执行到语句末尾结束!如果遇到break打断则马上退出switch语句,执行主路径的内容!
// 注意: switch语句的匹配是基于三等来匹配! 类型和值相等!
循环结构
// js的循环结构
// 循环:重复的执行一段相同的代码
// js中提供了以下几个循环语句
// while语句 do...while语句 for语句
while循环
// while循环
// 语法:
// while (表达式) {
// 循环体
// }
// while循环的注意事项:
// 1.必须设置循环控制变量
// 2.必须为循环控制变量赋初始值
// 3.每一次的循环体结束前应该更新循环控制变量
// 执行流程,首先判断表达式的true或者false,如果为true则执行循环体的代码,否则结束while循环
// 如果判断为true则执行循环体的代码,当循环体代码执行完毕时,再次判断表达式的真假!重复以上操作!直到表达式为false,退出while语句
// 打印以下 文本信息 hello world! 五次
// console.log('hello world!')
// console.log('hello world!')
// console.log('hello world!')
// console.log('hello world!')
// console.log('hello world!')
// while循环实现
// 1.设置循环控制变量
// let count = 1 // 2.设置初始值
// while (count <= 5) {
// console.log('hello world!')
// // 3. 更新循环控制变量
// count++
// }
// console.log('end—————')
// 练习1: 求1-100的和 利用while循环!
// let num = 1
// let sum = 0 // 求和变量 sum 保存每次+的结果
// while (num <= 100) {
// sum = sum + num
// num++
// }
// console.log(sum)
// 练习2: 求1-100的偶数和
// let num = 1
// let sum = 0
// while (num <= 100) {
// if (num % 2 === 0) {
// sum += num
// }
// num++
// }
// console.log(sum)
// 练习3: 从键盘上输入一个整数,求该数各位之和 如:758 ==》 7+5+8=20 | 1234 ==》 1+2+3+4 = 10
// 难点: 你不知道用户输入的数值位数!
// 758 ==》 7 5 8
// 758 ==》 8
// 75 ==》 5
// 7 ==》 7
// 758
// 758%10 == 8
// parsInt(758/10) == 75
// 75
// 75%10 == 5
// parsInt(75/10) == 7
// 7
// 7%10 == 7
// parsInt(7/10) == 0
// let num = Number(prompt('请输入一个大于0的正整数:'))
// let sum = 0
// while (num != 0) {
// sum = (num % 10) + sum
// num = parseInt(num / 10)
// }
// console.log(sum)
do while循环
// do...while循环语句
// 语法:
// do {
// 循环体
// }while(表达式)
// do...while循环的注意事项:
// 1.必须设置循环控制变量
// 2.必须为循环控制变量赋初始值
// 3.每一次的循环体结束前应该更新循环控制变量
// 执行流程,do...while循环,一开始先进行一次循环体代码的执行!然后进行表达式的判断!
// 如果为true 则继续执行循环体内容,重复操作!
// 如果为false 则结束do...while循环
// 打印hello world 5次
// let count = 1
// do {
// console.log('hello world!')
// count++
// } while (count <= 5)
// console.log('end——————')
// while (count <= 5) {
// console.log('hello world!')
// count++
// }
// do...while 和 while 的区别
// 如果do...while和while执行相同的代码逻辑!do...while至少比while多一次循环!
// do {
// console.log('hello world!')
// count++
// } while (false)
// while (false) {
// console.log('hello world!')
// count++
// }
for循环
// for 循环
// 语法:
// for(语句1;语句2;语句3){
// 循环体
// }
// 执行流程,
// for循环执行开始,先执行语句1,然后执行语句2,进行判断!
// 根据语句2的判读结果,true or false
// 如果为true,则执行循环体的内容,循环体内容执行完毕,跳到语句3并执行语句3的内容,语句3执行完毕后,又回到语句2再次进行判断!
// 直到语句2的结果为false,才会结束for循环
// 练习1: 利用for循环 求 1-100的偶数和
for (var sum = 0, i = 1; i <= 100; i++) {
if (i % 2 === 0) {
sum += i
}
}
// let 具备块级作用域
// var 不具备块级作用域
循环的嵌套
// 循环的嵌套,就是指多个循环语句进行嵌套使用!常见的 双重循环 , 三重循环!
// 注意:在实际应用中基本上不会超过三重循环!
// 双重循环, while和for while和while for和for while和do while....
// for (var day = 1; day <= 5; day++) {
// console.log(`今天是周${day}`)
// for (var count = 1; count <= 8; count++) {
// console.log(`这是今天的第${count}节课`)
// }
// }
// console.log('放假拉!.....')
// 练习1:打印矩形 利用双重循环
// *****
// *****
// *****
// *****
// 方法一: 利用 document.write()
for (var row = 1; row <= 4; row++) {
for (var col = 1; col <= 4; col++) {
document.write('*')
}
document.write('<br>')
}
//document.write() 浏览器中dom对象上方法!
// 方法二: console.log()
let str = ''
for (var row = 1; row <= 5; row++) {
for (var col = 1; col <= 5; col++) {
str += '*'
}
// 转义字符: 换行 '\n' 斜线 '\\' 水平制表符 '\t' tab键
str += '\n'
console.log(str)
console.log('')
str = ''
}
// 练习2:利用* 打印直角三角形 document.write(),console.log()
// *
// **
// ***
// ****
// *****
for (let i = 1; i <= 5; i++) {
for (let j = 1; j <= i; j++) {
document.write('*')
}
document.write('<br>')
}
//console.log() // 它就是一个api 利用它 实现 输出日志到控制台! 浏览器提供的!
continue和break
// continue 和 break关键字
// 两个关键字可以使得循环提前结束!
// break关键字
// 特点:直接结束当前包含break的循环语句!进入下一个步骤!
// continue关键字
// 特点:该关键字也可以结束循环,但是它只是结束该循环的本次内容!后续的循环继续执行!
// 拟人化
for (let num = 1; num <= 10; num++) {
if (num === 3) {
break
}
console.log(num)
}
for (let num = 1; num <= 10; num++) {
if (num === 3) {
continue
}
console.log(num)
}
console.log('end ____')
alert、confirm、prompt
// alert 弹窗提示 浏览器提供的 api 弹窗提示
// alert 它会阻塞页面的渲染和执行
// alert('请问????')
// console.log('3333')
// confirm 确认模态 弹出框 浏览器提供的 还具备返回值
// let res = confirm('确定还是取消??')
// console.log(res)
// 输入模态
// result = prompt('请输入姓名')
// console.log(result)
// alert(result)
// 上述api多用于调试
获取文档元素并修改其属性
// 浏览器为程序员提供了一个接口!
// 该接口可以访问页面中的所有元素节点!
// 该接口是一个对象!浏览器提供! document
// document是对象,那么对应的对象上是存在 属性或者方法的!
// console.log(document, typeof document)
// 利用document身上的方法可以获取到页面中的元素!
// 1.document.querySelector()
// 方法中的参数:是字符串类型,css的合法选择器
// css的选择器书写: .box div #01 div>span div span .....
// 该方法的返回值是符合css选择器下的第一个页面元素对象
// let elment = document.querySelector('div')
// let elment = document.querySelector('div>span')
// console.log(elment)
// 2.document.querySelectorAll()
// 方法中的参数:是字符串类型,css的合法选择器
// css的选择器书写: .box div #01 div>span div span .....
// 该方法的返回值是符合css选择器的所有页面元素对象,不管元素有多少个始终以 NodeList,伪数组的形式返回
// let arr = document.querySelectorAll('.box')
// console.log(arr)
// 3.document.getElementById() 通过元素的id属性值进行获取!
// let elment = document.getElementById('span01')
// console.log(elment)
// 4.document.getElementsByClassName() 通过元素的class属性值进行获取! 以 HTMLCollection 伪数组形式返回
// let arr = document.getElementsByClassName('box')
// console.log(arr)
// 5. document.getElementsByTagName() 通过元素的标签名进行获取! div span p h1.....
// let arr = document.getElementsByTagName('span')
console.log(arr)
通过元素对象获取和修改元素的属性
// 获取 div 元素
let div = document.getElementById('div01')
// 注意页面的元素都是对象类型,那么对象身上是具备属性和方法的!
console.log(div, typeof div)
// 通过api 查看 当前页面元素的所有属性!
console.dir(div)
// 页面是对象
console.log(div.title)
console.log(div.id)
// 注意:利用点语法或者[]是可以获取元素对象上所有已知或未知属性的值!除了class属性的值不能正常获取!
// 通过 class ==》 className来获取元素的class值
console.log(div.className)
console.log(div['id'])
// 修改页面元素的属性值
// div.title = 'xxxxxxxxxxxxxxxxxxx'
// div.className = 'box2'
元素对象的标签体属性
let box = document.querySelector('.box')
// console.log(box.className)
// 元素对象身上具备已知的属性 未知的属性!
// console.dir(box)
// innerHTML 和 innerText
// console.log(box.innerHTML) //
/*
<span>我是div的儿子</span>
*/
// console.log(box.innerText) // 我是div的儿子
// innerHTML是用于更改元素的标签体的内容,合法的字符会被浏览器自动解析为标签!
// innerText是用于更改元素的文本信息,该文本信息是不会被浏览器当作标签来正常解析的
// innerHTML
// box.innerHTML = '<span>我是div的儿子</span>'
// innerText
// box.innerText = '<span>我是div的儿子</span>'
通过简单的点击事件修改元素的标签体内容
let box = document.querySelector('.box')
let btn = document.querySelector('button')
// 为btn元素绑定一个点击事件
// 事件就是某个事情被触发了! 比如: 下雨 ==》 打伞 下课 ==》 吃饭 点击事件
// addEventListener(事件类型,事件处理函数)
btn.addEventListener('click', function () {
// console.log('我被点击了....')
// 当btn被点击时,修改box元素的标签体内容!
box.innerHTML = '我是被修改后的内容!'
})
数组的基础
// 数组,是存储一组数据的一个容器!
// 数组,是属于Object类型,通过typeof 检测是 'Object'
// 数组中可以同时存储不同类型的数据!只要是合法的js数据即可!多个数据之间使用',' 分隔!
// 数据中的每个数据可以称为 元素!数组的存储是有序存储的!利用元素的下标值进行访问!
// 1. 创建一个数组
// 方式一: 利用直接量进行创建, [] 推荐使用!
// let arr = ['a', 'b', true, 100]
// console.log(arr, typeof arr)
// 方式二: 利用构造函数 new Array()
// let arr = new Array(100, 200, 'HELLO', true)
// console.log(arr, typeof arr)
// 2. 获取数组中对应元素的值, 利用元素的下标!注意下标值是从 0 开始的!
// 语法: 数组[下标值]
// let arr = [100, 'a', 'b', true]
// console.log(arr[0])
// console.log(arr[1])
// console.log(arr[2])
// console.log(arr[3])
// console.log(arr[4]) // 如果超过下标范围,则返回undefined
修改数组元素的值
// 修改数组中对应元素的值 利用 赋值运算
// let arr = [100, 200, 300, 'hello']
// console.log(arr)
// arr[0] = 500
// console.log(arr)
// 思考:以下代码
let arr1 = [100, 200, 300, 'hello']
let arr2 = arr1
console.log(arr1, arr2) // [100,200,300,'hello'] [100,200,300,'hello']
arr1[2] = 800
console.log(arr1) // [100,200,800,'hello']
console.log(arr2) // [100,200,800,'hello']
// 解释?
// 数组是引用数据类型!数组的赋值本质上是地址值的赋值!所以利用地址值可以改变对应的数据!
数组的常见操作
// 数组的常见操作
// 所有的数组实例对象,都来自于Array构造函数! 所以所有的数组实例对象都具备相同的操作方法和属性
// let arr = [100, 200, 300, 'hello', true]
// 1.获取数组的长度 length属性
// console.log(arr.length) //返回当前数组的长度 元素的个数 数组的下标值范围:0 --- (arr.length-1)
// 2.添加元素到数组的末尾 push方法
// push方法是改变原数组的操作!
// arr.push('world!')
// console.log(arr)
// arr.push('xxx')
// console.log(arr)
// 3.删除数组末尾的元素 pop方法
// pop方法具备返回值,返回的就是被移除的末尾元素
// let res = arr.pop()
// console.log(res, arr)
// res = arr.pop()
// console.log(res, arr)
// 4.添加元素到数组的头部 unshift方法 原数组上操作数据! 无返回值
// arr.unshift('xxxx')
// console.log(arr)
// arr.unshift('yyyy')
// console.log(arr)
// 5. 删除数组头部的元素 shift方法 原数组上操作数据! 有返回值,被删除的元素
// let res = arr.shift()
// console.log(res, arr)
// 6. 在数组的任意位置实现,元素的添加,修改,删除! splice方法 在原数组上操作数据!
// 有返回值,返回值默认是一个空数组,如果有其他被删除的元素统一添加到该数组中
// splice(x,y,args...)
// x : 确定在数组的那个位置进行操作
// y : 是确实从对应位置开始删除的元素个数
// args: 用于更新的新元素列表
// let arr = [100, 200, 300, 'hello', true]
// 需求,我想在1索引的位置,删除2个元素,并用 新的元素进行替换
// arr.splice(1, 2, 'x', 'y', 'z')
// console.log(arr)
// 需求,我想在2索引的位置,删除1个元素,没有新元素替换
// arr.splice(2, 1)
// console.log(arr)
// 需求,我想替换索引3位置元素的值,更新
// arr.splice(3, 1, 'world!')
// console.log(arr)
// 需求,我想在索引0的位置,添加两个新元素
// let res = arr.splice(0, 0, 'x', 'y', 'z')
// console.log(arr, res)
// 7. concat 连接多个数组,并返回连接后的新数组,没有操作原数组!
// let arr1 = [100, 200]
// let arr2 = ['hello']
// [100,200,'hello']
// let arr3 = arr1.concat(arr2)
// console.log(arr3, arr1, arr2)
// let arr3 = arr1.concat(['a', 'b'], [1, 2], 'xxxxx')
// console.log(arr3)
// 利用concat方法实现数组浅拷贝
// let arr3 = arr1.concat([])
// console.log(arr3, arr1, arr3 === arr1)
// 以下方式为深拷贝
// let arr3 = arr1
// console.log(arr3, arr1, arr3 === arr1)
// 8. join方法 将数组中的各元素分散通过指定的字符进行连接,返回一个字符串数据!
// let arr = [100, 200, 300, 'hello', true]
// let str = arr.join('*&^*(^*&*&(')
// console.log(str)
// 9. includes 判断一个元素是否存在于当前数组中,存在则返回 true 不存在返回 false
// let arr = [100, 200, 'hello']
// let res = arr.includes(100)
// console.log(res)
// 10.判断元素是否存在,如果存在则返回第一个匹配的元素值的下标! 如果不存在则返回 -1
// indexOf 从左往右依次进行匹配!
// let arr = [100, 200, 'a', '3000', 'a']
// let res = arr.indexOf('a')
// console.log(res)
// 11. 判断元素是否存在,如果存在则返回第一个匹配的元素值的下标! 如果不存在则返回 -1
// lastindexOf 从右往左进行匹配
// let arr = [100, 200, 'a', '3000', 'a']
// let res = arr.lastIndexOf('a')
// console.log(res)
// 12. 数组的切片,获取数组的子数组 返回值,一个子数组!
// slice(开始下标,结束下标) 左闭右开的区间
// let arr = [100, 200, 300, 'a', 'b']
// let res = arr.slice(2, 3) // 0 1
// console.log(res)
// 总结: 注意以上的方法或者属性全都是数组的实例对象才能使用的!
多维数组
// 多维数组就是由多个数组进行嵌套表示!所形成的一个多维的数组形式!
// 二维数组
// let arr = [
// [100, 200],
// [300, 400],
// [500, 600],
// ]
// console.log(arr[0]) // [100,200]
// console.log(arr[1]) // [300,400]
// console.log(arr[2]) // [500,600]
// console.log(arr[0][0])
遍历数组
// 遍历: 就是去一个容器中,将该容器中的所有元素,访问一遍! 这种行为叫做遍历!
let arr = ['a', 'b', 'c', 'd', 'f']
// 需求遍历 arr
// 利用for循环来进行遍历 最传统的方式
for (let i = 0; i < arr.length; i++) {
// console.log(i)
console.log(arr[i])
}
对数组进行冒泡排序
let arr = [100, 2, 4, 56, 88, 91, 77]
// 冒泡排序:元素两两之间进行比较,根据大小的判断交换位置!最终实现数组的排序
// 双重循环
// for (let i = 0; i < arr.length; i++) {
// for (let j = 0; j < arr.length - i; j++) {
// if (arr[j] > arr[j + 1]) {
// let temp = arr[j]
// arr[j] = arr[j + 1]
// arr[j + 1] = temp
// }
// }
// }
// console.log(arr)
// 选择排序
// for (let i = 0; i < arr.length; i++) {
// for (let j = i + 1; j < arr.length; j++) {
// if (arr[i] < arr[j]) {
// let temp = arr[i]
// arr[i] = arr[j]
// arr[j] = temp
// }
// }
// }
// console.log(arr)
对数组进行倒置操作
// 倒置操作: ['a','b','c','d'] ==> ['d','c','b','a']
let arr = ['a', 'b', 'c', 'd']
// 方式一: 利用一个空数组
// let arr2 = []
// let len = arr.length
// for (let i = 0; i < len; i++) {
// arr2.push(arr.pop())
// }
// console.log(arr2)
// 方式二: 长度一半 首尾交换
// let temp
// for (let i = 0; i < parseInt(arr.length / 2); i++) {
// temp = arr[i]
// arr[i] = arr[arr.length - 1 - i]
// arr[arr.length - 1 - i] = temp
// }
// console.log(arr)
// 方式三:
// let arr2 = []
// for (let i = arr.length - 1; i >= 0; i--) {
// console.log(arr[i])
// arr2.push(arr[i])
// }
// console.log(arr2)
对数进行去重操作
// 去重操作
// ['a','b','c','a','y','b'] ==> ['a','b','c','y']
let arr = ['a', 'b', 'c', 'a', 'y', 'b'] // ['a','b','c','y','b']
// 方式一:利用空数组
// let arr2 = []
// for (let i = 0; i < arr.length; i++) {
// if (!arr2.includes(arr[i])) {
// arr2.push(arr[i])
// }
// }
// console.log(arr2)
// 方式二:利用 lastindexOf() splice()
// let index
// for (let i = 0; i < arr.length; i++) {
// index = arr.lastIndexOf(arr[i]) //index = 3
// while (index != i) {
// arr.splice(index, 1)
// index = arr.lastIndexOf(arr[i])
// }
// }
// console.log(arr)
js获取页面元素的样式属性值
let box = document.querySelector('.box')
// 需求,获取该元素的样式属性 比如 获取它的高度值!
// className title id .....value name .... style
// 1. 利用 elment.style 获取元素的样式对象!
// console.log(box.style, typeof box.style)
// // 利用样式对象 去获取 当前元素的属性值!
// console.log(box.style.width)
// console.log(box.style.height)
// console.log(box.style.backgroundColor) //注意:如果样式属性名是-连接的,则采用小驼峰方式获取!
// // 注意:利用element.style这种方式只能用于获取元素的 style属性中设置的样式值!
// console.log(box.style.border)
// 2.利用全局函数 getComputedStyle(elment) 返回 对象
// let res = getComputedStyle(box)
// console.log(res, typeof res)
// 利用 getComputedStyle(elment) 返回 对象 去获取当前元素正在应用的样式属性值
// console.log(res.width)
// console.log(res.height)
// console.log(res.backgroundColor)
// console.log(res.border)
// 总结: style属性的方式 和 getComputedStyle(elment)区别
// 1. style属性的方式只能去获取元素自身的style属性所设置的样式值
// 2. getComputedStyle(elment) 获取元素正在应用的样式属性值!
// 3. style属性是可读 可写 而 getComputedStyle(elment)是只读的不能重新赋值
// box.style.width = '500px'
// getComputedStyle(box).width = '500px'
点击元素更换背景色
<!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 {
width: 200px;
height: 200px;
background-color: red;
}
#div01 {
background-color: yellow;
}
</style>
</head>
<body>
<div class="box" id="div01"></div>
</body>
<script>
let box = document.querySelector('.box')
box.addEventListener('click', function () {
// box.style.backgroundColor = 'pink'
// box.style.width = '500px'
})
</script>
</html>
文档树
// 文档树
// 浏览器会将html文档中的标签,解析并转换为文档树
// 文档树是一个树形结构!html根标签,最外层的节点!其余的标签(节点)都是挂载于根节点上!
// 文档树中,由很多的节点类型!不只元素节点(标签节点)! 除了元素节点之外,还存在 一些其他的节点类型! 注释节点 文本节点 ....
// 注意:学习的重点以及操作是在元素节点!
创建节点
// 需求: 通过js代码在body中添加一个div元素节点
// 添加一个元素节点到已存在的节点中时,前提是 已经创建了对应的元素节点
// 1. 创建一个 div 元素节点 document.createElement()
// 参数要求, 数据类型 为 字符串 该字符串表示标签的名字!
// 创建一个div 'div' 'p' 'button'
let mydiv = document.createElement('div')
console.log(mydiv, typeof mydiv)
// 注意: 被创建出来的元素节点,它是不存在于文档树中! 需要把它插入或者添加到文档树中!
// 对元素节点的 操作: 创建 增 删 查 改
添加&插入节点
// 创建一个 div 元素
let mydiv = document.createElement('div')
// 在挂载前 初始化 元素节点
// mydiv.id = 'div01'
// mydiv.className = 'box'
// mydiv.innerHTML = '我是div元素'
// 挂载操作
// 添加节点 利用节点进行添加 , 把新创建的元素节点添加到具体的某个元素节点的内部!作为该元素节点的子节点!
// 获取body元素 document.body
// 方式一: appendChild(elment)
// 特点:该方法只会将元素添加到当前元素节点的末尾!
// 在挂载后 初始化 元素节点
// document.body.appendChild(mydiv)
// mydiv.id = 'div01'
// mydiv.className = 'box'
// mydiv.innerHTML = '我是div元素'
// 方式二: insertBefore(新节点元素,旧节点元素)
// 特点: 插入新的元素节点 到指定旧节点元素的前面
let box = document.querySelector('.box')
// document.body.insertBefore(mydiv, box)
// 如果insertBefore的第二个参数为 null 则将新元素节点添加到该父节点的末尾 等价于 appendChild
document.body.insertBefore(mydiv, null)
替换节点
// 需求:创建一个新的li元素把旧的li元素给替换掉!
// 1.创建一个新的li元素
let newli = document.createElement('li')
// let newli2 = document.createElement('li')
// let newli3 = document.createElement('li')
// let newli4 = document.createElement('li')
// let newli5 = document.createElement('li')
// newli.innerHTML = '新的li'
// 2.获取即将被替换的旧元素
// let oldli = document.querySelector('.first-li')
// 3.获取父节点,由父节点来完成替换操作! ul
let ul = document.querySelector('ul')
// 进行替换操作
// replaceChild(newnode,oldnode)
// ul.replaceChild(newli, oldli)
// 利用指定的新元素,去替换当前父元素下所有的子元素
// 指定的新元素个数不限!
ul.replaceChildren(newli1)
删除节点
// 删除操作
// 方式一:元素自删除!
let firstli = document.querySelector('.first-li')
// firstli.remove() // 元素自我删除
// 方式二: 利用父节点进行删除指定的子元素节点
// let ul = document.querySelector('ul')
// ul.removeChild(firstli)
查询操作
// 查询1: 通过指定元素,查询该元素的父节点
// let firstli = document.querySelector('.first-li')
// 通过元素节点的属性查询自己的父元素节点
// let res = firstli.parentNode // 节点
// console.log(res)
// console.log(firstli.parentElement === res)
// 查询2: 通过父元素查询它的所有子元素节点
let ul = document.querySelector('ul')
// 元素的属性 children 属性返回的是一个 伪数组
console.log(ul.children)
快速收集form表单数据
// 通过js动态获取 input的数据 value
// 1.获取所有的input元素
// 2.遍历input元素 拿到每一个input的value值
// let btn = document.querySelector('.btn')
// btn.addEventListener('click', function () {
// // console.log(666)
// let inputs = document.querySelectorAll('input[name]')
// for (let i = 0; i < inputs.length; i++) {
// console.log(inputs[i].value)
// }
// })
// 快速的方式 new FormData(表单对象)
// let btn = document.querySelector('.btn')
// btn.addEventListener('click', function () {
// // console.log(666)
// let formdata = new FormData(document.querySelector('form'))
// console.log(formdata.get('id'))
// console.log(formdata.get('name'))
// console.log(formdata.get('sex'))
// console.log(formdata.get('age'))
// })
通过数组渲染表格
<!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> <table border> <thead> <tr> <th>学号</th> <th>姓名</th> <th>性别</th> <th>年级</th> <th>班级</th> </tr> </thead> <tbody></tbody> </table> </body> <script> // 创建表格的数据 let data = [ { id: 0, name: '张三', sex: 'male', grade: '1年级', clazz: '2班', }, { id: 1, name: '李四', sex: 'female', grade: '6年级', clazz: '3班', }, { id: 2, name: '隔壁老王', sex: 'male', grade: '3年级', clazz: '2班', }, { id: 2, name: '隔壁老王', sex: 'male', grade: '3年级', clazz: '2班', }, { id: 2, name: '隔壁老王', sex: 'male', grade: '3年级', clazz: '2班', }, { id: 2, name: '隔壁老王', sex: 'male', grade: '3年级', clazz: '2班', }, { id: 2, name: '隔壁老王', sex: 'male', grade: '3年级', clazz: '2班', }, { id: 2, name: '隔壁老王', sex: 'male', grade: '3年级', clazz: '2班', }, { id: 2, name: '隔壁老王', sex: 'male', grade: '3年级', clazz: '2班', }, { id: 2, name: '隔壁老王', sex: 'male', grade: '3年级', clazz: '2班', }, { id: 2, name: '隔壁老王', sex: 'male', grade: '3年级', clazz: '2班', }, ] // 后端返回的json数据 let resdata = JSON.stringify(data) console.log(resdata) // 1.拿到json数据,应该先进行反序列化操作 data = JSON.parse(resdata) console.log(data) // 1.获取tbody元素 let tbody = document.querySelector('tbody') // 2.遍历后端返回的数组 // for (let i = 0; i < data.length; i++) { // console.log(data[i]) // tbody.innerHTML += ` // <tr> // <td>${data[i].id}</td> // <td>${data[i].name}</td> // <td>${data[i].sex}</td> // <td>${data[i].grade}</td> // <td>${data[i].clazz}</td> // </tr> // ` // } for (let i in data) { if (i == 2) break console.log(i) } // for in 会遍历原型链所有可枚举的属性! 遍历对象 数组 // for of 只能用于遍历 自身拥有 迭代器的数据! string array map set .... // 数组实例对象的各种遍历器 data.forEach((el) => { console.log(el); break }) </script> </html>
元素事件绑定问题
<!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> <div> <button>按钮</button> </div> </body> <script> let btn = document.querySelector('button') btn.addEventListener('click', function () { console.log(666) }) document.querySelector('div').innerHTML = '<button>按钮</button>' </script> </html>
通过动态指定class改变元素的样式
<!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 { width: 200px; height: 200px; background-color: pink; color: red; } </style> </head> <body> <div>我是div元素</div> <button>改变</button> <button>移除</button> </body> <script> let div = document.querySelector('div') let btns = document.querySelectorAll('button') btns[0].addEventListener('click', function () { // console.log(666) // div.style.width = '300px' // div.style.color = 'red' // div.style.backgroundColor = 'yellow' div.className = 'box' }) btns[1].addEventListener('click', function () { // console.log(666) // div.style.width = '300px' // div.style.color = 'red' // div.style.backgroundColor = 'yellow' div.className = '' }) </script> </html>
函数介绍和声明创建函数
// 函数:一段被封装好的可重复使用的代码段!并且可以实现某种功能!
// js中的函数,函数在js中在不同的环境下对其的叫法是不同!
// 函数的其他称呼:
// 方法
// 回调函数(callback)
// 构造函数
// 自执行函数(IIFE)
// 匿名函数
// 箭头函数 (lamda表达式)
// 无参函数
// 有参函数
// 比较函数 (主要用于对数据之间的比较,返回结果)
// 事件函数
// .....
// js中可以通过关键字 function进行函数的声明创建
// 语法结构
// 1.声明创建一个函数
// function 函数名(形参列表){
// 函数体
// }
// 函数的声明,在声明时,函数体内部的代码是不会执行的!
function sayHello() {
console.log('hello world!')
}
// 2.调用函数\执行函数
// 语法: 函数名()
// 注意:函数名 + () 才能执行对应的函数!
sayHello()
无参函数和有参函数
无参函数:对应的某个函数,不具备形参列表!不需要额外的参数传入!该函数称为无参函数
有参函数:函数在定义时,明确指定了形参列表!后续的函数执行中也需要外部的数据!
// 注意: a ,b 就是形参变量 (形式参数)
function add(a, b) {
console.log(a + b)
}
// 调用函数
// 200,300 就是 实参 实际参数!一一对应关系
add(200, 300)
函数的返回值
// 函数的返回值,大部分函数都是具备返回值!
// 返回值代表的是该函数执行后,对数据的处理结果! 然后利用 return语句 进行返回!外部可以使用函数的返回值!
// 如果函数,没有return语句,默认该函数的返回值是 undefined
// 注意: return语句的特点
// 1.return语句后可以是任何合法的js数据类型!
// 2.return语句具有中断函数的功能,函数的执行过程中如果碰到return 那么直接结束该函数的执行!
函数的值传递和引用传递
// 值传递,内部函数的数据操作不会影响外部传入的数据!
// let num = 100
// function change(mynum) {
// mynum += 10
// }
// change(num)
// console.log(num)
// ---------------------------------------------
// 引用传递,实参和形参的改变会相互影响!
// let obj = {
// num: 100,
// }
// function change(myobj) {
// myobj.num += 100
// }
// // 调用 函数 change
// change(obj)
// console.log(obj.num)
方法
// 方法:方法的本质其实也是一个函数,只不过该函数是作为某个对象的属性存储的!
let person = {
name: '张三',
age: 18,
sayHello: function () {
console.log('你好我是张三!')
},
}
console.log(person)
// 调用方法 方法名()
// person.sayHello()
函数表达式
函数表达式 : 函数也是一种数据类型!引用数据类型!Object ==> typeof 检测出来 Function
注意:函数是一种数据,该数据是存储在堆空间中的!
回调函数
// 回调函数:函数最终通过某种手段执行了,但是不是你让它执行的!这种就是回调函数!
// function fun(callback) {
// for (let i = 0; i < 10; i++) {
// if (i === 5) {
// callback()
// break
// }
// }
// }
// // fun函数 需要传入一个 函数(回调函数)作为参数
// fun(function () {
// console.log('哈哈我执行了,你不知道吧!')
// })
// let btn = document.querySelector('button')
// btn.addEventListener('click', function () {
// console.log('66666')
// })
自执行函数
// let fun = function () { // console.log(666) // } let num = 100 // IIFE 自执行函数 ;(function () { console.log(666) })() // 声明并创建 function fun() {} // 创建函数 let res = function () {} let obj = { // 创建一个函数 函数表达式 fun: function () {}, }
箭头函数
// 箭头函数: 书面称呼, lamda表达式 ,俗称是箭头函数
// 箭头函数是在es6中新加入的一种特殊的函数形式!
// 与function函数的不同
// 1. 创建方式不同 不需要function关键字进行声明修饰!
// 箭头函数的创建 语法
// (形参列表)=>{
// 函数体
// }
// 2.箭头函数,通常不能像function函数那样,直接进行声明然后利用函数名进行调用
// 箭头函数通常是依附于某个变量或者某个对象上的属性
// 2.1 作为某个变量的值,保存箭头函数
// let fun = () => {
// console.log(666)
// }
// fun()
// // 2.2 作为某个对象的方法
// let obj = {
// say: () => {
// console.log('say...')
// },
// }
// obj.say()
// // 2.3 作为一个callback进行 函数的传递使用
// btn.addEventLisener('click', () => {})
// function fun() {}
// ;() => {}
// ;(() => {
// console.log(666)
// })()
// 3. 箭头函数中不具备自己的this关键字
// 箭头函数的书写小知识:
// ;() => {
// console.log(6666)
// }
// 第一个: 当形参个数有且只有一个时,()是可以省略的
// let fun = num => {
// console.log('fun....', num)
// }
// fun(50)
// 第二个: 当函数体内部只有 一条语句时, {} 是可以省略的
// let fun = num => console.log('fun....', num)
// fun(5000000)
// 第三个: 当函数体内部只有 一条语句时,该函数的返回值默认就是 该语句的结果
// let fun = num => num+200
// let fun = (num)=>{
// return num+200
// }
// let res = fun(100)
// console.log(res)
作用域
// 作用域: 指变量或者函数的作用范围!
// js中目前存在三种作用域
// 1. 全局作用域 es6之前
// 2. 函数作用域 es6之前
// 3. 块级作用域 {} es6之后才有 块级作用域
// 全局作用域
// 在函数外的区域,整个 script 脚本区域 所在区域,称为全局作用域
// 显式的全局变量
// var num = 100
// console.log(num)
// function fun() {
// console.log(num)
// }
// fun()
// 隐式的全局变量
// num = 200 // js自动的在全局的作用域 声明了 一个变量 var num
// console.log(num)
// 函数作用域
// 函数体内部声明的变量或者函数,具备函数作用域
// var num = 500
// function fun() {
// var num = 300 // 函数作用域下 num 变量
// console.log(num)
// }
// console.log(num) // 500 全局作用域下 num
// fun() // 函数作用域下的 num
// 块级作用域
// 块级作用域的变量 只能通过 let 或者 const 进行声明 才会存在块级作用域
// {
// const num = 100
// // num 在那个 块下声明 {}
// console.log(num)
// }
// console.log(num)
// for (var i = 0; i < 5; i++) {}
// console.log(i)
// let btns = document.querySelectorAll('button')
// for (let i = 0; i < btns.length; i++) {
// btns[i].addEventListener('click', () => {
// console.log(i)
// btns[i].style.width = '200px'
// })
// }
// // {
// // btns[i].addEventListener('click', () => {
// // console.log(i)
// // })
// // }
// // {
// // btns[i].addEventListener('click', () => {
// // console.log(i)
// // })
// // }
// // i = 3
作用域链
// 作用域链:通过作用域的链式关系,进行查找对应的 变量 和 函数
// 如果沿着作用域链一直寻找,直到在全局作用域下都没有找到对应的变量或者函数 就会报错!
// 注意:作用域链的查找规则是 从内到外!查找!
// var num = 500
// function fun() {
// console.log(num)
// }
// fun()
// var num = 500
// function fun() {
// var num = 400
// function fun2() {
// var num = 300
// console.log(num)
// }
// fun2()
// }
// fun()
// {
// let num = 500
// {
// let num = 300
// console.log(num)
// }
// }
预解析
// 预解析: js代码在真正的执行前,会先进行一个操作!该操作称为 预解析!
// 预解析主要涉及两个内容
// 当前作用域下的var变量 和 function 函数进行提升!
// console.log(num)
// var num = 500
// js引擎在真正执行代码前会将以上的代码先进行预解析
// 预解析后的代码情况
// var 变量的提升操作
// var num
// console.log(num)
// num = 500
// console.log(num)
// function函数的提升
// fun()
// function fun() {
// console.log(666)
// }
// 预解析操作
// function fun() {
// console.log(666)
// }
// fun()
// 变量和函数的提升谁更靠前 ! 函数的提升优于变量的提升
// console.log(fun)
// var fun = 300
// function fun() {
// console.log(666)
// }
// console.log(fun)
// 预解析
// function fun() {
// console.log(666)
// }
// var fun
// console.log(fun)
// fun = 300
// console.log(fun)
// var num = 200
// var num // js看来是无效的声明 因为在全局作用域下已经声明过一个 num 变量了 并且有值了!
// console.log(num)
let和const的暂时性死区
// let 的变量不具备提升操作
// console.log(num) // Cannot access 'num' before initialization
// let num = 200
// console.log(num) // num is not defined
// // let num = 200
// let 和 const 所修饰的变量不具备提升操作!但是存在一个'暂时性死区'
// console.log(num) // Cannot access 'num' before initialization
// const num = 500
var、let、const的区别
总结:
var 、 let 、const 三者的区别
1. var存在变量提升操作,var不具备块级作用域,var可以在同一作用域重复声明同名的变量或者函数
2. let不存在变量提升操作,let具备块级作用域,let存在暂时性死区,let不允许在同一作用域声明同名的变量和函数
3. const不存在变量提升操作,const具备块级作用域,const存在暂时性死区,const不允许在同一作用域声明同名的变量和函数,const声明的同时必须赋!
函数的封装
// 技术 技巧
// 技术: 每一个知识点的学习和掌握 for语句 定时器 while循环 if 闭包 多敲!多练!多问!多思考!
// 技巧: 编程的思想 思维!代码的冗余问题!高内聚,低耦合原则! 经验的积累!项目的累积!错误叠加!
// 高内聚: 代码语句不是零散,散落!而是高度集中的! 函数封装!
// 低耦合: 耦合功能快之间是否连接的特别缜密!低耦合就是要求你不要连接的特别缜密!
// 编程高手,菜鸟的区别?
// 看你的代码 if switch 出现的频率!
// let arr = []
// let num = 200
// // if (num > 100) {
// // arr.push(200)
// // }
// // num > 100 ? arr.push(200) : ''
// num > 100 && arr.push(200)
// console.log(arr)
// 将某段重复执行的代码,利用函数进行封装!方便后续的使用!
// 需求: 求两个数的和
// let num1 = Number(prompt('请输入第一个数:'))
// let num2 = Number(prompt('请输入第一个数:'))
// let sum = num1 + num2
// alert(sum)
// 把以上的代码封装成一个函数
// function add() {
// let num1 = Number(prompt('请输入第一个数:'))
// let num2 = Number(prompt('请输入第一个数:'))
// let sum = num1 + num2
// alert(sum)
// }
// add()
封装一个求任意圆面积的函数
function getArea() { let r = Number(prompt('请输入一个圆的半径:')) let area = r ** 2 * 3.14 return area } alert(getArea()) // 注意: // 1.封装时尽可能的不要将代码段写在函数外!然后再移植到函数内!应该直接将该函数的内容,写在函数体内! // 2.函数命名规范!函数是为了实现某种功能!应该给使用它的人清晰的表达!见名知义! // 3.函数内部所使用的数据,大部分都是通过函数调用时传入的参数! function getArea(r) { return r ** 2 * 3.14 } let res = getArea(5) console.log(res)
localStorage
// localStorage 数据持久化到浏览器中,关闭窗口或浏览器,都不会消失 // localStroage 将数据永久性的存储到 浏览器中! 以键值对的形式 // 设置数据, key 和 value 数据类型必须是字符串类型 localStorage.setItem('name', '张三') // 设置数据 [] localStorage['age'] = 18 // 读取数据 console.log(localStorage.getItem('name')) console.log(localStorage['age']) // http://127.0.0.1:5501/JavaScript/day07/04_localStorage.html // 域名 127.0.0.1 // 域名 www.bilibili.com
sessionStorage
// sessionStorage 将数据临时性的存储到 浏览器中! 以键值对的形式 ! 窗口关闭 数据就消失
// 设置数据, key 和 value 数据类型必须是字符串类型
sessionStorage.setItem('name', '张三')
// 设置数据 []
sessionStorage['age'] = 18
// 读取数据
console.log(sessionStorage.getItem('name'))
console.log(sessionStorage['age'])
// http://127.0.0.1:5501/JavaScript/day07/04_localStorage.html
// 域名 127.0.0.1
// 域名 www.bilibili.com
执行上下文
// 执行上下文环境:js代码在执行的过程中,会存在一个环境!js引擎会将js代码,分别设置一个执行环境! // 执行上下文环境的分类:三大类 // 1. 全局执行上下文 // 2. 函数执行上下文 // 3. eval()执行上下文 (忽略,了解!) var num = 100 console.log(666) 10 + 20 function say1() { // 函数的执行上下文 console.log(666) } function say2() { // 函数的执行上下文 console.log(666) } say1() console.log(66666) say2() console.log(777777)
this关键字
// this关键字,可以理解为 语文的 '这' 代词! 是一个变化的东西!
// this的变化是有规律的!
// 寻找this,判断this
// 1.在浏览器环境中的全局上下文中,this永远指向的是 顶层对象 window
// 2.在浏览器环境中函数执行上下文中,this指向的也是 顶层对象 window , 严格模式除外! 函数执行上下文,设置了严格模式,那么this指向的 undefined
// 3.如果函数是被某个对象进行调用时,那么该函数(方法)中的this指向的是,它的调用对象(调用者)!而非持有者!
// 4.构造函数中this,指向的是新创建出来的一个该构造函数类型的 实例 {} 空对象!
// 5.事件对象的事件处理函数中的this,指向的是 当前被绑定的元素对象,仅适用于 function函数
// 6.箭头函数,它不存在自己的this,它的this是该箭头函数被创建时,当时的执行上下文环境中的this!并且永不改变包括this的三大劫持手段!(类似于‘印随效应’)
// 小技巧: 如何判断函数形式执行还是方法形式执行 // 调用时的表达式形式, // 函数名() // 对象.方法() // function fun() { // 'use strict' // console.log(this, typeof this) // } // fun() // var obj = { // name: 'obj1', // fun: function () { // 'use strict' // console.log(this) // }, // } // obj.fun() // new fun() 把函数作为构造函数进行调用、使用 let btn = document.querySelector('button') // btn.addEventListener('click', function () { // console.log(this) // }) // let obj = { // name: 'obj', // fun: function () { // console.log(this) // obj // btn.addEventListener('click', () => { // console.log(this) // }) // }, // } // obj.fun() // var obj1 = { // name:'obj1', // fun:function(){ // console.log(this.name) // } // } // var obj2 = { // name:'obj2', // myfun:obj1.fun // } // obj2.myfun()
严格模式
# 严格模式
w3school 文章: https://www.w3schools.cn/js/js_strict.asp
## 为什么要使用严格模式
为了代码更规范,避免一些错误与 `js` 历史问题所产生的歧义
## 严格模式中不准做的事情
开启严格模式
- 全局执行上下文 开启
- 函数执行上下文 开启
- 未声明变量就直接赋值
- `x = 12`
- 对象也一样 `x = {a: 1, b: 2}`
- 直接删除变量
- `delete x`
- 重复定义参数名
- `function fn(a, a) {}`
- 不允许使用 8 进制数
- `let x = 010`
- 不允许使用八进制转义字符
- `let x = '\010'`
- 不允许赋值只读属性
- ```js
'use strict'
const obj = {}
Object.defineProperty(obj, 'x', { value: 0, writable: false })
obj.x = 3.14
```
- ```js
'use strict'
const obj = {}
const obj = {
get x() {
return 0
},
}
obj.x = 3.14
```
- 删除不允许删除的属性
- `delete Object.prototype`
- `eval` `arguments` 不能重复定义变量
- `let eval = 3.14`
- 不能使用 `with` 语法
- with (Math){x = cos(2)};
- 不能用 `eval()` 函数创建变量
- `eval ("let x = 2")`
- \*`this` 关键字在函数内,默认为 `undefined`
- ```js
function fn() {
console.log(this) // => undefined
}
```
严格模式测试
'use strict'
// 隐式的声明 全局的作用域 var num
// num = 100
// console.log(num)
// delete 关键字 对象 属性 非严格模式 delete 变量
// var num = 100
// delete num
// var obj = {
// a: 100,
// b: 200,
// }
// console.log(obj.a)
// delete obj.a
// console.log(obj.a)
// function fun(a, a) {}
// js中表示各进制的数据
// 0b ==》 二进制
// 0 ==》 八进制
// 0x ==》 十六进制
// var num = 053
// console.log(num)
构造函数
// 构造函数:构造函数也是函数!构造函数的本义是用于构造一个实例对象!并不是像普通函数一样为了实现某种功能!
// 任何函数都可以作为构造函数使用!前提是 它是否被 new 关键字调用!
// 构造函数的命名:软性规定,建议构造函数的首字母大写
// 平时创建一个对象 json对象
// 以下的方式创建对象的问题已经暴露
// 解决方式:通过自定义的构造函数,去构建对象!
// var person1 = {
// name: '张三',
// age: 18,
// sex: '男',
// }
// // 使用以上方式,构建一个对象比较慢!不灵活!
// // 如果需要批量的构建一个相同类型的对象?该方式的效率很低!
// var person2 = {
// name: '李四',
// age: 20,
// sex: '男',
// }
// var person3 = {
// name: '小红',
// age: 20,
// sex: '女',
// }
// // typeof 检测的时候 无法辨别该实例对象的 具体类型
// console.log(typeof person1)
// console.log(typeof person2)
// console.log(typeof person3)
// var car = {
// color: 'black',
// price: 2000,
// }
// console.log(typeof car)
// // 以上的创建对象的方式 底层是 这样实现
// var obj = new Object()
// console.log(obj, typeof obj)
function Person(name,age,sex) {
this.name = name
this.age = age
this.sex = sex
}
function Car(color,price) {
this.color = color
this.price = price
}
// var p1 = new Person() // 构造函数中,new关键字会自动创建一个该类型的实例对象!
// var car1 = new Car()
// // 如果调用构造函数 不需要额外的参数时 可以省略括号 ,建议不要省略
// var p2 = new Person
// console.log(p1, car1, p2)
var p1 = new Person('张三',18,'男')
var p2 = new Person('李四',20,'男')
var car1 = new Car('black',2000)
console.log(p1,p2,car1)
Person()
构造函数和普通函数的区别
// 构造函数和普通函数的区别:
// 1.构造函数中默认返回值已经构造完成的对象
// 2.普通函数默认返回值是 undefined
// 3.构造函数需要搭配new关键字进行使用
// 4.构造函数的目的不是为了实现某种功能,而是去快速构造某一类型的实例对象
// 5.构造函数中的this指向的是new关键字所创建的该构造函数类型的对象实例! {}空对象
// 注意:构造函数的返回值问题
// 1.构造函数中默认是省略 return语句 ,并且默认返回的是构建完成的实例对象 {}
// 2.如果存在return语句,则返回的内容分情况讨论:
// 情况一: return 返回的 数据类型是 基本值数据类型 Number、Boolean 、Sring...,则完全无视这个return,
// 情况二: return 返回的 数据类型是 引用数据类型 则正常的将该数据进行返回
// 为了避免上述问题的存在,建议大家构造函数中的return就不要写了!
new关键字
// new关键字是配合构造函数使用:
// new关键字,做了几件事情:
// 1.new关键字会创建一个该构造函数的实例对象,一开始是空的{}
// 2.new关键字会将刚才创建的实例对象的__proto__属性指向为 构造函数所保存的 prototype指向的对象
// 3.new关键字会将构造函数中的this 指向为 该实例对象
// 4.最终返回这个 实例对象
this的劫持
// 正常情况下,this的指向都是符合 六大规则! // 非正常情况下,人为可以将this强行的改变! // 强行改变this的手段,我们称为对this的劫持! // this的劫持方法: call() 、 apply() 、 bind() // 以上的三个方法都属于,Function实例对象身上的方法! // call劫持 // var obj1 = { // name:'obj1', // fun:function(a,b){ // console.log(this,a,b) // } // } // var obj2 = { // name:'obj2' // } // 正常情况调用 // obj1.fun(100,200) // call方法调用 // obj1.fun.call(obj2,100,200) // apply劫持 // var obj1 = { // name:'obj1', // fun:function(a,b){ // console.log(this,a,b) // } // } // var obj2 = { // name:'obj2' // } // // 正常情况调用 // obj1.fun(100,200) // // apply() // obj1.fun.apply(obj2,[100,200]) // 总结:call和apply方法的区别 // call和apply使用方式基本一致,唯一的不同在于实参的传递方式 // call是将多个实参以逗号分隔,依次传入函数中 // apply是将多个实参以数组的形式,一次性传入函数中 // 思考:利用call和apply可以劫持箭头函数中的this吗? // var obj1 = { // name:'obj1', // fun:()=>{ // console.log(this) // } // } // var obj2 = { // name:'obj2' // } // // 正常情况调用 // obj1.fun() // // call 或 apply // obj1.fun.call(obj2) // obj1.fun.apply(obj2) // 总结:箭头函数this不能被劫持 // bind劫持是利用bind方法返回一个新的函数! // 劫持该函数中的this,相对于call和apply来说,它们是操作自身的函数!bind的操作新的函数! var obj1 = { name: 'obj1', fun: function (a, b) { console.log(this, a, b) }, } var obj2 = { name: 'obj2', } // 正常情况下 // obj1.fun() // bind劫持 // let res = obj1.fun.bind() // console.log(res) res是bind方法执行后返回来的新函数, 新的函数 ,这个新函数长的和fun函数一模一样 obj1.fun.bind(obj2, 100, 200)()
js垃圾回收机制
垃圾回收:JavaScript程序在运行的过程中,随着运行时间的增加,那么会相应的产生一些垃圾数据,垃圾回收机制主要是
定时的去清理这些垃圾数据,避免内存溢出、泄露导致程序崩溃!
内存的溢出:
内存的泄露:
注意:垃圾回收这个动作不需要人为的去管控,它是由js引擎垃圾回收的模块负责
如何定义垃圾:
- 标记清除:假设所有的变量或者函数等其他数据,一开始就认为他们不是垃圾!当他们产生了某种变化后,就会被打上标记,标记为垃圾
- 引用计数:当引用型数据,没有再被任何引用时,引用链条为0的时候!就自动判定为垃圾数据
正常情况下:
- 全局作用域下的变量、函数在程序执行完毕后才会销毁
- 局部作用域下的变量、函数,当该局部作用域执行完了!结束后,就销毁对应的变量以及函数
- 引用数据当引用链条数量为0的时候,也会被销毁
小提示:
垃圾回收机制并不是JavaScript语言独有,很多编程语言都具备
- java、python、JavaScript
- c c++ 人为的控制,人为的定期去是释放内存
闭包
<script> // 闭包,这个东西! 道可道,非常道!名可名,非常名! // 闭包:把一些数据进行封装!包裹!形成一个独立的空间,该空间只会被能访问到该空间的‘人’使用 // 如何才会产生一个闭包: // 1.假设有两个函数,A函数,B函数,并且B函数是在A函数的内部进行声明的!B函数是被嵌套声明的! // 2.B函数内部,使用了一些A函数中才会存在的数据!通过作用域链找到了A函数中的一些数据! // 3.最终当A函数执行完毕后,把B函数 ‘交’出去了! 交出去的方式有多种:1.return 2.直接把它赋值给外部的变量 // 这个时候,就产生了闭包! // 什么是闭包? // 闭包就是一个函数在其他函数的内部嵌套声明,并且该函数内部使用了上级函数的数据!并且该函数被返回出去了! // 闭包的优点: // 1.使用闭包可以形成对立的空间,避免变量名污染问题 // 2.利用闭包,可以在函数外,也能访问到函数内部的数据! // 闭包的缺点: // 1.闭包的产生有很多时候是隐式产生的,最终会造成内存泄漏 // function A(){ // var num = 100 // function B(){ // // console.log(num) // num++ // console.log(num) // } // return B // } // 正常的情况下 // A() // A函数执行完毕后,根据垃圾回收机制, num变量 和 B函数 应该被销毁 // 能够通过任何的手段访问到 num 和 B吗? 正常情况下是不能有任何的手段访问到num和B函数的 // 产生了闭包的情况下 // let C = A() // 清除闭包 让变量指向为null 空 // C = null // C() // 101 // C() // 102 // C() // 103 // let F = C // F() // 104 // let D = A() // D() // 101 // 情况二: // function A(){ // var num = 100 // function B(){ // var num = 200 // num++ // console.log(num) // } // return B // } // // 产生闭包没有? 没有产生闭包 // let C = A() // C() // 201 // C() // 201 // C() // 201 // 情况三: // function A(){ // var num = 100 // function B(){ // num++ // console.log(num) // } // C = B // } // var C // A() // C() // 101 // C() // 102 // C() // 103 // // 产生闭包没有?产生了闭包 // 情况四: // function A(){ // var num = 100 // function B(){ // console.log(num) // } // return B // } // let C = A() // 帮助理解闭包的例子: // 1.把被交出去的那个函数 , 拟人化 // 2.这个人,离家出走, 打包东西! // 3.人出去了,打包的东西也跟着走了! // 情况五: // function A(){ // var num1 = 100 // function B(){ // var num2 = 200 // function C(){ // console.log(num1++,num2++) // } // return C // } // return B() // } // let D = A() // 产生闭包没有?产生了闭包 // D() // D() // D() // D() // 假设 function A() { let num = 10 function B() { console.log(num) } return B } let C = A() let D = C // 刚才A执行时在内存中所创建的 num 和 B 被销毁没有? // 1. 被销毁 2.没有被销毁 // 1.如果没有被销毁 num 和 B函数空间 存在的 // 利用了闭包这个空间 保存了 函数中运行时所需要用到的数据!防止函数无意义的执行! C() // 2.如果被销毁 num 和 B函数空间 不存在的 C // UNDEFINDE C() 报错
定时器
// js中的定时器、计时器:
// 作用:规定一段时间,然后执行某一段代码!
// js提供了两种创建定时器的方式:
// 全局函数:setTimeout(一次性的) setInerval(永久性的)
// 这两个方法都是同步方法!而传入的callback是异步的,不会阻塞主线程
// 以上两个函数都需要传入两个参数:
// 参数一:规定时间后,需要执行的函数 callback
// 参数二:规定多少时间开始执行代码 单位是ms 是忽略!
// setTimeOut() 一次性的
// setTimeout(() => {
// console.log(666)
// }, 5000)
// setInerval() 重复的执行
// setInterval(() => {
// console.log(666)
// }, 1000)
// 计时器被创建后都会产生一个唯一的计时器编号,可以利用对应的编号关闭计时器
// 计时器的id,由 setTimeOut() 或者 setInerval() 的返回值决定
// 1.关闭setTimeout所创建的计时器
// let timer = setTimeout(() => {
// console.log(666)
// }, 1000)
// // console.log(timer)
// // 利用计时器编号关闭,setTimeout创建的计时器
// // clearTimeout(timer)
// // timer:对应的计时器编号
// clearTimeout(timer)
// 2.关闭setInerval所创建的计时器
// let timer = setInterval(() => {
// console.log(666)
// }, 1000)
// clearInterval(timer)
//-----------------------------------------------------
// 感受:异步
// console.log(111)
// console.log(222)
// console.log(333)
// setTimeout(() => {
// console.log(444)
// }, 0)
// console.log(555)
// 444 111 222 333 555
// for (var i = 0; i < 5; i++) {
// setTimeout(() => {
// console.log(i)
// }, 0)
// }
元素的自定义属性
<!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> <div class="box" id="div01" add="100" data-reduce="200" data-a="200" data-b="300"> 我是div元素 </div> <!-- 标签元素,是具备属性的! 标签属性 在html中大部分使用的都是,官方预定义的属性!比如: id title class src...... 但是,在实际的开发中,需要用到一些,自定义的属性! 自定义的属性作用: 保存数据! 临时保存到页面中,浏览器中! --> <!-- 如何创建自定义属性 --> <!-- 1. 直接在元素的开始标签中,书写自定义的属性名以及赋值操作 --> <!-- 2. 利用data-* 形式创建自定义属性 --> <!-- 如何读取自定义属性的值 --> <script> // 如何读取官方的元素属性? let box = document.querySelector('.box') // 需求:读取class的属性值 console.log(box.className) // 需求:读取id的属性值 console.log(box.id) // 读取自定义的元素属性值 // 需求:读取add自定义属性的值 // 注意:自定义属性的值,不能通过点语法进行获取,需要使用元素对象的方法进行获取! console.log(box.getAttribute('add')) // 需求:读取data-reduce自定义属性的值 console.log(box.getAttribute('data-reduce')) console.log(box.getAttribute('class')) console.log(box.getAttribute('id')) // 修改、设置一个元素的自定义属性 // 利用setAttribute会将数据,隐式的转换为string类型 box.setAttribute('add', true) // box.getAttribute('add') // console.log(typeof box.getAttribute('add')) box.setAttribute('class', 'boxxxxx') box.setAttribute('data-reduce', '700') // 利用setAttribute为元素添加新的自定义属性 box.setAttribute('mydata', 100) // 特别的data-属性的读取方式 console.log('------------------------') console.log(box.dataset.reduce) console.log(box.dataset.a) console.log(box.dataset.b) </script> </body> </html>
classList数组
<!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> div { width: 200px; height: 200px; background-color: red; } .box1 { background-color: pink; } .box2 { font-size: 50px; } .box1box2 { background-color: yellow; } </style> </head> <body> <div>div元素</div> <button>还原</button> <button>变色</button> <button>增大字体</button> <script> // 动态的改变box元素样式 let box = document.querySelector('div') // 拿到三个按钮 let btns = document.querySelectorAll('button') console.log(box.classList) // 为按钮绑定事件 btns[0].addEventListener('click', () => { // box.className = '' // classList 当前元素的样式类列表 box.classList.remove('box1') box.classList.remove('box2') }) btns[1].addEventListener('click', () => { // box.className = 'box1' box.classList.add('box1') }) btns[2].addEventListener('click', () => { // box.className += ' box2' box.classList.add('box2') }) </script> </body> </html>
时间对象
// 时间对象:JS提供的一种针对处理时间相关的内容的对象!
// 比如:一个商品的打折时间! 1.31 - 2.7 打折时间! 倒计时!
// 需求:获取当前用户的 星期数
// 需求:获取今年的年份,判断闰年平年!
// .....
// 以上和时间相关的操作!信息!都需要利用js所提供的时间对象来获取!或者操作!
// 创建一个时间对象 利用 JS提供的 Date(构造函数、类) ===》 new Date类 实例化一个时间对象
// 四种创建方式
// 方式一:无任何构造参数
// let date = new Date() // 返回一个当前系统时间的,时间对象
// console.log(date, typeof date) // Tue Jan 31 2023 11:11:54 GMT+0800 (中国标准时间)
// // 注意:不要过多的关注,浏览器所展示的时间对象的样式!
// 方式二: value 时间戳 返回一个由当前时间戳与格林威治时间(标准时间的插值)所代表的一个时间对象
// let date = new Date(59000)
// console.log(date, typeof date) // 1970-1-1-8:00:59
// 时间戳:当前时间与标准的格林威治时间的毫秒差值,称为时间戳!
// 格林威治:英国的小镇 1970-1-1-00:00:00 之间的差值 1970-1-1-00:00:58 58秒==》58000毫秒 这个58000毫秒就是我们说的时间戳
// 1970-1-1-00:00:00 1970-1-1-00:00:01 08:00:01
// 方式三: dataString 时间字符串 该方式不推荐使用!各浏览器之间对时间字符串的定义有些差入!
// 时间字符串的参考:https://www.w3.org/TR/NOTE-datetime
// let date = new Date('1997-10-19')
// console.log(date)
// 方式四: 依次传入 年 月 日 时 分 秒 毫秒 进行构造时间对象
// let date = new Date(2023, 1, 31, 11, 34, 48, 1500)
// let date = new Date(2023, 10)
// console.log(date)
// 特殊的使用方式 不使用 new Date()
// Date()函数 返回的是当前时间对象的字符串形式!
// let date1 = Date()
// let date2 = new Date()
// console.log(date1, typeof date1, date2, typeof date2)
操作时间对象
// 操作时间对象 // 1.获取对应的时间数据 let date = new Date() // 14:23:1:578 console.log(date) // 1- 获取时间对象的年份 console.log(date.getFullYear()) // 2- 获取时间对象的月份, 注意月份是从 0开始计算的 0代表1月 console.log(date.getMonth() + 1) // 3- 获取时间对象的日 一个月的第几天 console.log(date.getDate()) // 4- 获取时间对象的 星期数 注意:范围是0-6 0代表星期天 console.log(date.getDay()) // 5- 获取时间对象的 小时数 console.log(date.getHours()) // 6- 获取时间对象的 分钟数 console.log(date.getMinutes()) // 7- 获取时间对象的 秒数 console.log(date.getSeconds()) // 8- 获取时间对象的 毫秒数 console.log(date.getMilliseconds()) // 2.设置对应的时间数据 // 将以上的所有方法的 get 替换为 set // date.setFullYear(2000) // console.log(date) // 获取时间对象的时间戳 // console.log(Date.now()) //获取当前系统时间的时间戳 14:23:1:804 console.log(date.getTime()) // 获取当前时间对象的时间戳
数学函数
// js还提供了,数学相关的运算方法!这些方法都是基于 Math 全局函数的! // 注意:Math函数不能作为构造函数使用! 所有是无法实例化一个数学对象! console.log(Math) // abs() 求一个数的绝对值 console.log(Math.abs(-10)) console.log(Math.abs(10)) // cos sin tan 三角函数 acos asin atan 反三角函数 求弧度值! // floor 地板数,对一个数向下取整 console.log(Math.floor(3.8)) // 3 console.log(Math.floor(3.12)) // 3 console.log(Math.floor(-2.8)) // -3 // ceil 天花板数, 对一个数向上取整 console.log(Math.ceil(3.8)) // 4 console.log(Math.ceil(3.12)) // 4 console.log(Math.ceil(-2.8)) // -2 // max 返回当前参数列表中最大值 console.log(Math.max(100, 200, 300, 1, 77, 800)) // min 返回当前参数列表中最小值 console.log(Math.min(100, 200, 300, 1, 77, 800)) // pow 求一个数的幂 console.log(Math.pow(2, 5)) // sqrt 开平方根 console.log(Math.sqrt(9)) // round 对一个数四舍五入 console.log(Math.round(3.1)) console.log(Math.round(3.8)) console.log(Math.round(4.5)) // random 随机数, 随机返回一个 0-1之间的小数 包括0,不包括1 伪随机! console.log(Math.random())
扑克牌游戏
<!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> <script> // 斗地主 // 游戏规则 // 一副扑克牌: 54张 // 三位玩家:两个农民,一个地主 // 发牌! // 农民1: 17 // 农民2: 17 // 地主: 17 // 地主牌: 3 // 开始游戏! // 1. 准备一副54张扑克牌 // 2. 洗牌 打乱顺序 排序是随机的 // 3. 发牌 17张 17张 20张 // 4. 打印农民1的牌 // 5. 打印农民2的牌 // 6. 打印地主的牌 // ♥ ♠ ♣ ♦ // console.log('♥5') // console.log('♠5') // console.log('♦5') // console.log('♣5') // 红桃2 - 红桃A // 黑桃2 - 黑桃A // 方片2 - 方片A // 梅花2 - 梅花A let color = ['♥', '♠', '♣', '♦'] let numbers = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'] let puker = ['joker', 'JOKER'] let prepare_puker = [] for (let i = 0; i < color.length; i++) { for (let j = 0; j < numbers.length; j++) { puker.push(color[i] + numbers[j]) } } console.log(puker) // 洗牌 // 洗牌方式一: // for (let i = 0; i < 54; i++) { // let index = Math.floor(Math.random() * puker.length) // prepare_puker.push(puker[index]) // puker.splice(index, 1) // } // 洗牌方式二: // let arr = [1, 0, -1] // puker.sort((a, b) => { // // let index = Math.floor(Math.random() * arr.length) // // return arr[index] // return Math.random() - 0.5 // }) // console.log(puker) // let player01 = puker.slice(0, 17) // let player02 = puker.slice(17, 34) // let player03 = puker.slice(34) // console.log(player01, player02, player03) // 不洗牌直接发牌: let player01 = [] let player02 = [] let player03 = [] for (let i = 0; i < 54; i++) { let index = Math.floor(Math.random() * puker.length) prepare_puker.push(puker[index]) if (!(player01.length === 17)) { player01.push(puker[index]) } else if (!(player02.length === 17)) { player02.push(puker[index]) } else { player03.push(puker[index]) } puker.splice(index, 1) } console.log(player01, player02, player03) </script> </body> </html>
elment元素offset、client系列的属性
<!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 { width: 200px; height: 200px; padding: 5px; border: 2px solid red; background-color: pink; margin-top: 50px; margin-left: 50px; } .father { /* position: relative; */ } /* .big_box { position: relative; } */ </style> </head> <body> <!-- <div class="big_box"> <div class="father"> <div class="box"></div> </div> </div> --> <div class="box"></div> <script> let box = document.querySelector('.box') // box ==> 是一个dom元素 elment元素 console.dir(box) // offset系列的属性 5个 获取当前元素的相关的偏移数据 // 注意:offset属性具体的内容! 首先明确,该元素的 offsetParent 是谁? // 1. offsetParent console.log(box.offsetParent) // 默认情况下,元素是相对于 body元素进行偏移的! // 注意:offsetParent 指向的是距离当前元素最近的并且开启了定位的祖先元素!如果没有任何的元素符合这一条件那么,offsetParent默认指向body元素 // 2. offsetTop 当前元素的顶部距离offsetParent元素的距离 返回值是 number类型 console.log(box.offsetTop) // 3. offsetLeft 当前元素的左侧部分距离offsetParent元素的距离 返回值是 number 类型 console.log(box.offsetLeft) // 4. offsetWidth 当前元素的可见框的 宽度大小 width + padding + border console.log(box.offsetWidth) // 200 + 2 + 10 // 5. offsetHeight 当前元素的可见框的 高度大小 height + padding + border console.log(box.offsetHeight) // 200 + 2 + 10 console.log('--------------------') // client系列属性 4个 当前元素自身的一些数据值 // 1. clientTop 当前元素的顶部边框大小 number类型 元素的padding 到 边框的之间 间距 console.log(box.clientTop) // 2. clientLeft 当前元素的左侧边框大小 number类型 console.log(box.clientLeft) // 3. clientWidth 当前元素的除border属性外的可见框宽度大小 width + padding console.log(box.clientWidth) // 4. clientHeight 当前元素的除border属性外的可见框高度大小 height + padding console.log(box.clientHeight) // 特殊情况:一个元素 只设置了 宽和高 // box.offsetWidth === box.clientWidth </script> </body> </html>
事件
// 事件:某个事情,特殊的一种情况!
// js中可以利用某个事件的触发!去相应的执行某一断代码!
// 事件的三要素:
// 1. 事件源
// 2. 事件类型
// 3. 事件处理函数
// JS中如何为一个元素绑定事件
// 绑定事件的三种方式:
// 1. 利用 元素标签 自身的 on* 属性(事件属性) 进行事件的绑定 完全不建议使用
// 语法: onclick = '函数形式的字符串' ==》 onclick = 'add()'
function test(num) {
console.log('html标签的事件属性')
}
// 2. 在js脚本中利用元素对象的事件属性进行,数据的绑定 偶尔用!
// let btn = document.querySelector('button')
// // btn元素对象上自身的事件属性进行绑定事件
// console.dir(btn)
// btn.onclick = function () {
// console.log('事件属性方式')
// }
// 3. 通过事件监听器,进行元素的事件绑定 强烈推荐的!
// let btn = document.querySelector('button')
// btn.addEventListener('click', () => {
// console.log('监听器方式')
// })
事件的解绑
<!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> <!-- 方式一: --> <button onclick="test()">按钮一</button> <!-- 方式二: --> <button class="btn2">按钮二</button> <!-- 方式三: --> <button class="btn3">按钮二</button> <script> // 解绑一: // let count = 1 // let btn = document.querySelector('button') // function test() { // // 需求:button点击事件只能 有效的点击5次 // if (count === 5) { // // 解绑事件, 对button按钮进行事件的解绑 // btn.onclick = null // } // console.log('按钮一', count++) // } // 解绑二: // let btn2 = document.querySelector('.btn2') // let count = 1 // // 为btn2绑定事件 // btn2.onclick = function () { // console.log(this) // // 需求:button点击事件只能 有效的点击5次 // if (count === 5) { // // 解绑事件 // this.onclick = null // } // console.log('按钮二', count++) // } // 解绑三: let btn3 = document.querySelector('.btn3') let count = 1 btn3.addEventListener('click', function test() { // console.log(this) if (count === 5) { // 解绑事件 监听移除函数 btn3.removeEventListener('click', test) } console.log('按钮三', count++) }) // function mytest() { // console.log(456456) // console.log(456456) // console.log(456456) // console.log(456456) // console.log(456456) // console.log(456456) // console.log(456456) // } // btn3.addEventListener('click', mytest) // btn3.removeEventListener('click', mytest) </script> </body> </html>
为一个元素绑定多个相同的事件
// 事件属性 和 事件监听器的区别
// let btn = document.querySelector('button')
// btn.onclick = function () {
// console.log('click1')
// }
// btn.onclick = function () {
// console.log('click2')
// }
// btn.onmousemove = function () {
// console.log('mousemove')
// }
// 事件属性的方式相同类型的事件,只能绑定一个事件处理函数
// let btn = document.querySelector('button')
// function test1() {
// console.log('click1')
// }
// function test2() {
// console.log('click2')
// }
// btn.addEventListener('click', test1)
// btn.addEventListener('click', test2)
// 事件监听的方式可以为同一个元素绑定多个相同类型的事件,并且指定不同的处理方式
事件分类
<!DOCTYPE html> <html> <head> <style> .box { width: 300px; height: 300px; background-color: gold; } .box2 { width: 100px; height: 100px; background-color: pink; position: absolute; bottom: 0; } </style> </head> <body> <div> <!-- <img src="./事件冒泡与捕获过程.png" /> --> </div> <form onsubmit="return false"> <div> <label>姓名:<input name="name" /></label> </div> <div> <label >班级: <select name="clazz"> <option>1班</option> <option>2班</option> <option>3班</option> </select> </label> </div> </form> <div> <button class="btn1">点我</button> </div> <div class="box" tabindex="1"> <!-- <div class="box2"></div> --> Lorem ipsum dolor, sit amet consectetur adipisicing elit. Exercitationem soluta minima sequi consectetur voluptatum reprehenderit, dolorem explicabo quaerat quo porro, omnis quia mollitia repudiandae labore veritatis ad nam, quibusdam sapiente. </div> </body> <script> // 参考:https://developer.mozilla.org/zh-CN/docs/Web/Events // https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener // 函数 获取页面的 元素 通过选择器的方式 function $(selector) { return document.querySelector(selector) } // 资源事件 // load: 资源加载完成后就会触发 // $('img').addEventListener('load', () => { // console.log('图片加载完成') // }) // // error: 资源加载失败时触发 // $('img').addEventListener('error', () => { // console.log('图片加载失败') // }) // // 焦点事件 // // 焦点事件只用于表单元素 // focus : 获取焦点事件 let inp = $('form input[name=name]') // inp.addEventListener('focus', () => { // console.log('获取到焦点了') // }) // // blur: 失去焦点事件 // inp.addEventListener('blur', () => { // console.log('失去焦点了') // }) // // 鼠标事件 // // click:鼠标左键点击事件 // let btn1 = $('.btn1') // btn1.addEventListener('click', () => { // console.log('点击事件触发了') // }) // // contextmenu: 鼠标右键点击事件,右键点击改元素是触发的事件 let box = $('.box') let box2 = $('.box2') // box.addEventListener('contextmenu', () => { // console.log('鼠标右键被点击了') // }) // // dblclick: 双击事件 // box.addEventListener('dblclick', () => { // console.log('双击事件触发了') // }) // // mousedown: 鼠标按下事件 // box.addEventListener('mousedown', () => { // console.log('mousedown') // }) // // mouseup: 鼠标松开事件 // box.addEventListener('mouseup', () => { // console.log('mouseup') // }) // // mouseenter\mouseover 鼠标移入事件 // box2.addEventListener('mouseenter', () => { // console.log('mouseenter') // }) // box2.addEventListener('mouseover', () => { // console.log('mouseover') // }) // // mouseleave\mouseout 鼠标移出事件 // box2.addEventListener('mouseleave', () => { // console.log('mouseleave') // }) // box2.addEventListener('mouseout', () => { // console.log('mouseout') // }) // // mousemove: 鼠标移动事件 // box.addEventListener('mousemove', () => { // console.log('mousemove') // }) // // wheel : 鼠标滚轮事件 // box.addEventListener('wheel', () => { // console.log('wheel') // }) // change:当值发生变化时触发,多用于表单元素 // let select = document.querySelector('form select') // select.addEventListener('change', () => { // console.log('change') // }) // inp.addEventListener('change', () => { // console.log('input change') // }) // // input: 输入框输入字符时触发该事件 // inp.addEventListener('input', () => { // console.log('正在输入....') // }) // // 按键事件 // // keydown: 按钮按下事件 // document.body.addEventListener('keydown', () => { // console.log('keydown') // }) box.addEventListener('keydown', () => { console.log('keydown') }) //???? // inp.addEventListener('keydown', () => { // console.log('keydown') // }) // keyup:按钮抬起事件 // document.body.addEventListener('keyup', () => { // console.log('keyup') // }) // // keypress: 按钮按住不放事件 // document.body.addEventListener('keypress', () => { // console.log('keypress') // }) </script> </html>
事件对象
// 事件对象:一个事件被触发后!浏览器对应的会自动产生一个事件对象!并且该事件对象是具备类型的!
// 鼠标事件、键盘事件、资源事件....
// 事件对象的作用:事件对象上存放了一些与该事件产生时的一些数据或者方法!
// 事件对象如何使用?
// 事件对象在事件函数被执行时,浏览器会自动的向该事件函数传入对应的事件对象!只需要利用一个形参变量来接受即可!
// 一般这个形参变量,命名为: event ==> ev
// 注意:不同类型的事件对象,所保存的数据的不一样的!有些属性是任何事件对象都具备的,比如: type
// 也有很多的属性是该事件对象所独有的!
// 事件函数调用执行时,一般不会传入其他的参数!
// 因为事件函数的第一个实参是传入的事件对象!
document.addEventListener('click', (event) => { console.log(event) }) document.addEventListener('keydown', (event) => { console.log(event) })
鼠标事件对象常用属性
<!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 { width: 200px; height: 200px; background-color: yellow; position: absolute; left: 30px; top: 80px; } body { width: 5000px; height: 2000px; } </style> </head> <body> <!-- <button>按钮</button> --> <div class="box"></div> <script> // 鼠标事件相关类型 click dbclick mousemove ... document.addEventListener('click', (ev) => { // console.log(ev) // button 属性 判断点击的左键还是右键 0左键 1右键 // console.log(ev.button) // type 属性 返回的是当前 事件对象的具体事件类型: click dbclick keydown keyup.... // console.log(ev.type) // }) // box绑定点击事件 let box = document.querySelector('.box') box.addEventListener('click', (ev) => { ev.preventDefault() ev.stopPropagation() console.log(ev) // console.log(ev) // offsetX offsetY // console.log('offsetX:', ev.offsetX) //返回点击的目标点,与当前元素的左侧距离 number // console.log('offsetY:', ev.offsetY) //返回点击的目标点 与当前元素的顶部距离 number // console.log('-------------') // clientX clientY console.log('clientX:', ev.clientX) //返回点击的目标点,与当前页面窗口的左侧距离 number console.log('clientY:', ev.clientY) //返回点击的目标点 与当前页面窗口的顶部距离 number // console.log('-------------') // screenX screenY // console.log('screeX:', ev.screenX) //返回点击的目标点,与当前电脑屏幕,设备屏幕的左侧距离 number // console.log('screenY:', ev.screenY) //返回点击的目标点 与当前电脑屏幕,设备屏幕的顶部距离 number // console.log('-------------') // pageX pageY console.log('pageX:', ev.pageX) //返回点击的目标点,与当前页面窗口的实际间隔的左侧距离! 滚动条区域也算进去! number console.log('pageY:', ev.pageY) //返回点击的目标点,与当前页面窗口的实际间隔的左侧距离! 滚动条区域也算进去! number }) </script> </body> </html>
事件执行机制-冒泡
<!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> .father { width: 300px; height: 300px; background-color: yellow; } .son { width: 200px; height: 200px; background-color: red; } </style> </head> <body> <div class="father"> <div class="son"></div> </div> <script> // 事件的冒泡:事件的传递过程! 事件是可以进行传递的! // father 盒子 son 盒子 绑定了点击事件 // son盒子在father盒子的内部 点击son时候 son点击会触发 father触发 事件会传递!传递的过程是 由内到外 ! 冒泡! // 事件的冒泡是建立在统一个事件类型上的! 比如 click...bdlclick...等 let father = document.querySelector('.father') let son = document.querySelector('.son') father.addEventListener('click', (ev) => { console.log('father-click') }) son.addEventListener('click', (ev) => { console.log('son-click') }) document.body.addEventListener('click', (ev) => { console.log('body-click') }) </script> </body> </html>
事件执行机制-捕获
<!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> .father { width: 300px; height: 300px; background-color: yellow; } .son { width: 200px; height: 200px; background-color: red; } </style> </head> <body> <div class="father"> <div class="son"></div> </div> <script> // 事件的捕获:事件的传递过程! 事件的传递过程分为 捕获阶段和冒泡阶段 // 默认情况下所有的事件都是的冒泡阶段触发的,但也有例外可以让事件提前在捕获阶段触发! // 冒泡过程: 从内到外 // 捕获过程: 从外到内 // 一个完整的事件触发,必定经历两个阶段,1.捕获阶段 2.冒泡阶段 // 如果想实现某个元素的事件处理函数在捕获阶段就执行,需要利用 addEventListenter 方法的第三个参数 // 第三个参数是一个布尔值,默认情况是 false 代表不在捕获阶段执行! true 代表在捕获阶段执行! let father = document.querySelector('.father') let son = document.querySelector('.son') father.addEventListener( 'click', (ev) => { console.log('father-click') }, true ) son.addEventListener('click', (ev) => { console.log('son-click') }) document.body.addEventListener( 'click', (ev) => { console.log('body-click') }, true ) // 1. body-click 2. son-click 3.father-click // 1.body-click 2.father-click 3.son-click </script> </body> </html>
envent对象的targetcurrentTarget属性的区别
<!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 {
width: 200px;
height: 200px;
background-color: red;
}
.box1 {
width: 100px;
height: 80px;
background-color: yellow;
}
.box2 {
width: 100px;
height: 80px;
background-color: pink;
}
</style>
</head>
<body>
<div class="box">
<button>按钮</button>
<div class="box1">
<span>xxxxxxxx</span>
</div>
<div class="box2"></div>
</div>
<script>
// target 和 currentTarget 存储的也是两个elment元素
let box = document.querySelector('.box')
box.addEventListener('click', (ev) => {
console.log(this) // box 自身 box
console.log(ev.target)
console.log((ev.currentTarget === this) === box)
console.log('---------------')
// this ==> 当前处理函数的事件源 this指向是被绑定事件的元素
// ev.target ==> 触发该事件产生的对象元素
// ev.currentTarget ==》 正在处理该事件的元素对象
})
</script>
</body>
</html>
事件的代理_委托
<!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>
* {
list-style: none;
}
.bigbg li {
width: 200px;
height: 100px;
background-size: 200px 100px;
border-radius: 15px;
margin: 0 10px;
}
.bg1 {
background-image: url(img/bg1.jfif);
float: left;
}
.bg2 {
background-image: url(img/bg2.jfif);
float: left;
}
.bg3 {
background-image: url(img/bg3.jfif);
float: left;
}
</style>
</head>
<body>
<ul class="bigbg">
<li class="bg1" data-src="img/bg1.jfif"></li>
<li class="bg2" data-src="img/bg2.jfif"></li>
<li class="bg3" data-src="img/bg3.jfif"></li>
</ul>
</body>
<script>
var body = document.querySelector('body')
// var lis = document.querySelectorAll('li')
// lis[0].addEventListener('click', function () {
// body.style.backgroundImage = "url('./bg1.jfif') "
// })
// lis[1].addEventListener('click', function () {
// body.style.backgroundImage = "url('./bg2.jfif') "
// })
// lis[2].addEventListener('click', function () {
// body.style.backgroundImage = "url('./bg3.jfif') "
// })
// li[下标值] ===> xxxxxxx 循环的方式,统一设置! 没必要单独为每一个元素设置相同的逻辑操作!
// 利用冒泡机制,实现了 事件的委托 事件的代理!
let ul = document.querySelector('.bigbg')
ul.addEventListener('click', (ev) => {
console.log('click')
console.log(ev.target)
body.style.backgroundImage = `url(${ev.target.dataset.src})`
})
</script>
</html>
通过js代码触发事件
let btn = document.querySelector('button')
btn.addEventListener('click', (ev) => {
console.log('btn-click', ev)
})
// click由‘谁’触发? 当前的用户
// 不需要用户来触发 btn-click 事件
// 需求: 代码开始执行后 2秒 主动触发 btn的click事件
setTimeout(() => {
// 时间到了 触发btn的点击事件
console.log('希望触发btn的点击事件')
// js代码主动触发元素的事件
// 方式一:
// btn.click() // 真实的去触发了某个事件 会产生相应的事件对象
// btn.onclick() // 本质上没有触发事件 只是调用一次 事件函数! 不存在事件对象
//方式二:
// 1.手动创建一个事件对象的实例
// 2.为某个元素派遣该事件对象
let event = new Event('click')
btn.dispatchEvent(event)
}, 2000)
阻止事件的冒泡
<!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>
.father {
width: 300px;
height: 300px;
background-color: yellow;
}
.son {
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
// 事件默认是允许冒泡的!冒泡的过程会传递给上层的元素,导致上层元素不得不触发该事件,并且执行事件函数
let father = document.querySelector('.father')
let son = document.querySelector('.son')
father.addEventListener('click', (ev) => {
ev.stopPropagation()
console.log('father-click')
})
son.addEventListener('click', (ev) => {
// 阻止当前的事件继续向上冒泡
ev.stopPropagation()
console.log('son-click')
})
document.body.addEventListener('click', (ev) => {
console.log('body-click')
})
</script>
</body>
</html>
阻止元素的默认事件
let btn = document.querySelector('button')
btn.addEventListener('click', (ev) => {
// 阻止默认事件的发生
ev.preventDefault()
console.log(6666)
})
自定义事件
let btn = document.querySelector('button')
btn.addEventListener('click', (ev) => {
console.log('btn-click')
})
// 绑定一个自定义的事件,我自己创建的一个事件
btn.addEventListener('xxx', (ev) => {
console.log('btn-xxx')
})
// 注意: 自定义的事件,用户是无法触发的!
// 自定义的事件,只能通过 js代码进行触发!
setTimeout(() => {
// 触发 btn身上的 xxx 事件
// 1.创建一个自定义的事件对象 通过 构造函数 CustomEvent
// let event = new Event('') // new Event 本质是用于创建官方的事件类型的 click dblclike keyup ....
let myevent = new CustomEvent('xxx')
// 2.派遣该事件对象
btn.dispatchEvent(myevent)
}, 2000)
鼠标的移入移出事件的区别
<!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 {
width: 200px;
height: 200px;
background-color: yellow;
}
.father {
width: 300px;
height: 300px;
background-color: #bfa;
}
.son {
width: 100px;
height: 100px;
background-color: #cfcfcf;
}
.test_box {
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<div class="test_box"></div>
</body>
<script>
let father = document.querySelector('.father')
let son = document.querySelector('.son')
let test_box = document.querySelector('.test_box')
// mouseover(移入) 和 mouseout(移出)
// test_box.addEventListener('mouseover', (ev) => {
// console.log('鼠标移入..')
// })
// test_box.addEventListener('mouseout', (ev) => {
// console.log('鼠标移出..')
// })
// mouseenter(移入) 和 mouseleave(移出)
// test_box.addEventListener('mouseenter', (ev) => {
// console.log('鼠标移入..')
// })
// test_box.addEventListener('mouseleave', (ev) => {
// console.log('鼠标移出..')
// })
// mouseover & mouseout 和 mouseover 和 mouseout 区别如下:
// mouseover(移入) 和 mouseout(移出)
// 进入或者离开当前元素都会触发
// 进入或者离开当前元素的后代元素也会触发
// father.addEventListener('mouseover', (ev) => {
// console.log('鼠标移入..')
// })
// father.addEventListener('mouseout', (ev) => {
// console.log('鼠标移出..')
// })
// mouseenter(移入) 和 mouseleave(移出)
// 进入或者离开当前元素才会触发
// 进入或者离开当前元素的后代元素不会触发
father.addEventListener('mouseenter', (ev) => {
console.log('鼠标移入..')
})
father.addEventListener('mouseleave', (ev) => {
console.log('鼠标移出..')
})
</script>
</html>
js的对象继承问题
// 语法糖:方便程序的开发,简洁一些语法!
// 直接量的方式创建
let arr1 = []
let arr2 = [1, 2, 3]
let arr3 = ['a', 'b', 'c']
// 以下三个语句打印的是什么?
console.log(arr1.push) // function
console.log(arr2.push) // function
console.log(arr3.push) // function
// arr1 arr2 arr3 是什么数据类型? Object
// JS中 万物皆对象!
// 对象是一种实例化的数据!描述的是现实中的事物! 对象是具体的!
// 对象是类的实例! 类是抽象的 对象是具像的! ‘人’ 类 ==》 ‘张三’ 、 ‘王五’ 、
// 对象身上具备属性和方法!
// 属性:描述该对象的数据
// 方法:描述该对象的行为
// 人类 == 》 属性: 五官的大小 身高 性别 年龄 肤色 .....
// 人类 ==》 方法(行为): 吃饭 睡觉 打豆豆....
// arr1 arr2 arr3 对象
// 肯定就是具备 属性 和 方法
// arr1 arr2 arr3 他们是同一类型的对象 !他们都属于同一个类! 数组 Array
// 创建数组真实的语法:
// let arr = new Array(1, 23, 500, 800) 本质的数组创建
// arr1 arr2 arr3 同属于 Array类
// arr1 arr2 arr3 具备相同的属性 和 方法
// console.log(arr1.push) // function
// console.log(arr2.push) // function
// console.log(arr3.push) // function
console.log(arr1.push === arr2.push)
console.log(arr2.push === arr3.push)
// 为什么数组实例对象 一经创建 就具备了一些属性和方法 即使该数组是空的!
// 继承! 不要重复的为每个实例添加属性和方法! 他们属于共同的类 可以直接继承 类的 属性 和 方法!
let str = 'hello world!'
console.log(str.push) // undefinde new String()
console.log(str.split()) // str = new String()
显示原型和隐式原型属性
// JS中任何的一个实例对象都具备一个 隐式原型属性 __proto__
// JS中所有的function函数身上都具备一个 显示原型属性 prototype
// function是不是一个对象?
// function身上同时具备 __proto__ 和 prototype
// prtotype 和 __proto__ 是两个属性!存储的是 对象类型的数据! Obeject类型
// 创建一个构造函数 Person
function Person(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
this.sayHello = () => {
console.log(this.name, '@')
}
}
// 创建一个Person类型的实例对象
let p1 = new Person('张三', 18, '男')
let p2 = new Person('李四', 20, '男')
console.log(p1, p2)
// p1 和 p2 共同的属性 name,age,sex
// p1 和 p2 具备一些公有的属性 或者 公有的方法
// 打印查看 Person 显示原型属性
console.log(Person.prototype, 'Person函数对象的显示原型属性')
// console.log(Person.__proto__, typeof Person.__proto__)
// 打印查看 P1 实例对象 隐式原型属性
console.log(p1.__proto__, 'p1的隐式原型属性指向的对象')
// 证明: Person.prototype === p1.__proto__
console.log(Person.prototype === p1.__proto__)
console.log(Person.prototype === p2.__proto__)
console.log(p1.__proto__ === p2.__proto__)
console.log('----------------------------')
let arr1 = new Array(100, 200)
let arr2 = new Array(500, 200)
console.log(arr1.__proto__ === Array.prototype)
console.log(arr2.__proto__ === Array.prototype)
console.log(arr1.__proto__ === arr1)
console.log(arr1.push === arr1.__proto__.push)
// 继承! js中的继承是利用了隐式原型对象
// 以及原型链的概念,最终实现了实例对同一构造函数上的方法或者属性的继承!
演示继承
function Person(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
}
console.log(Person.prototype)
Person.prototype.sleep = function () {
console.log('睡觉....')
}
console.log(Person.prototype)
// 构建实例对象
let p1 = new Person('张三', 18, '男')
let p2 = new Person('李四', 20, '男')
console.log(p1, p2)
// console.log(p1.__proto__)
// console.log(p2.__proto__)
p1.sleep()
p2.sleep()
// console.log(p1.sleep === p2.sleep)
原型链
// 实例对象身上__proto__ 存储的是什么数据类型? Object
// 原型链
// 每一个实例对象上都具备 __proto__ 原型对象
// 当一个对象在自身上找不到对应的属性或者方法时,会沿着__proto__原型对象身上去寻找! obj {}
// 如果往上一级的__proto__身上还是找不到想要的属性或者方法 obj.__proto__
// 那么它会继续沿着当前这一级__proto__继续寻找! obj.__proto__.__proto__
// .... obj.__proto__.__proto__.__proto__
// 沿着原型链最终找到 null 就结束! 如果已经访问到null 都还没有找到想要的属性或者方法 则放回 undefined
// 以上描述寻找的过程就称为 原型链!
显示原型对象和隐式原型对象的区别
function Person() {}
console.log(Person.prototype)
console.log(Person.__proto__)
console.log(Person.prototype === Person.__proto__)
// 函数中的prototype属性是为了保证所有经过该函数所构造的实例对象能够继承该prototy属性所指向的对象!临时的保存!
let p1 = new Person()
// 1.P1你长大了被创建出来了!
// 2.我这里有一样要交给你! prototype 钥匙 ===》 ‘东西’
// 3.这个东西你准备放在哪里,不要搞丢了!
// 4.p1说你放在我的 __proto__ 上面吧! 不会搞丢的!
let p2 = new Person()
// 1.P2你长大了被创建出来了!
// 2.我这里有一样要交给你! prototype 钥匙 ===》 ‘东西’
// 3.这个东西你准备放在哪里,不要搞丢了!
// 4.p2说你放在我的 __proto__ 上面吧! 不会搞丢的!
// let Person = new Function()
// 1.Person你长大了被创建出来了!
// 2.我这里有一样要交给你!Function 身上 prototype 钥匙 ===》 ‘东西’
// 3.这个东西你准备放在哪里,不要搞丢了!
// 4.Person说你放在我的 __proto__ 上面吧! 不会搞丢的!
console.log(Object.prototype.__proto__, '@')
console.log(p1.__proto__.__proto__ === Object.prototype)
// 注意:prototype 属性 可以随意的更改 使用!
// JS代码中,尽可能的不要去 动 __proto__ 隐式元素对象
私有属性和私有方法
// 私有属性或者私有方法,指的是该属性和方法只能在类中使用,不能够通过实例化的方式进行点语法的获取
class Person {
country = '中国'
// 定义私有属性 #变量名
#num = 100
// 构造器,构造函数 必须的!
constructor(name, sex, age) {
this.name = name
this.sex = sex
this.age = age
this.mynum = this.#num
this.xxx = this.#sayHello()
this.#xxx = 500
}
// Person类中 {}
// 所定义的方法直接就挂载到 Person.prototype对象上
eat() {
console.log('eat...')
console.log(this.#num)
this.#sayHello()
}
sleep() {
console.log('sleep...')
}
play_dd() {
console.log('play_dd...')
}
// 定义私有的方法 #方法名
#sayHello() {
console.log('hello...', '@')
return 200
}
}
let p1 = new Person('张三', '男', 18)
console.log(p1)
// console.log(p1.country)
// console.log(p1.name)
// console.log(p1.sex)
// console.log(p1.age)
p1.eat()
// p1.sleep()
// p1.play_dd()
// console.log(p1.#num)
// p1.#sayHello() err
静态属性和静态方法
// 静态属性和静态方法,指的是该属性和方法只能由类本身进行调用!
class Person {
// 定义一个静态属性 static 属性名
static name = 'Person'
// 构造器,构造函数 必须的!
constructor(name, sex, age) {
this.name = name
this.sex = sex
this.age = age
}
// Person类中 {}
// 所定义的方法直接就挂载到 Person.prototype对象上
eat() {
console.log('eat...')
}
sleep() {
console.log('sleep...')
}
play_dd() {
console.log('play_dd...')
}
// 定义一个静态方法 static 方法名
static test() {
console.log('test...')
}
}
let p1 = new Person()
// console.log(p1.xxx)
// p1.test()
console.log(Person.name)
Person.test()
子类与父类之间的继承语法
// 定义一个类 Person 人类 name sex age ... 吃饭 睡觉 ....
class Person {
constructor(name, sex, age) {
this.name = name
this.sex = sex
this.age = age
}
eat() {
console.log('eat....')
}
}
// 定义一个类 Stutent 学生类 name sex age sid clazz.. 吃饭 睡觉 上课....
// 没有继承的写法
// class Student {
// constructor(name, sex, age, sid, clazz) {
// this.name = name
// this.sex = sex
// this.age = age
// this.sid = sid
// this.clazz = clazz
// }
// eat() {
// console.log('eat....')
// }
// // 学生类的方法 上课
// study() {
// console.log('上课中....')
// }
// }
// 继承 子类与父类的继承!
// Student 继承于 Person
// 继承的写法
class Student extends Person {
constructor(name, sex, age, sid, clazz) {
// 调用一次 父类的 constructor
// 关键字 super
super(name, sex, age)
this.sid = sid
this.clazz = clazz
}
study() {
console.log('上课中...')
}
}
let stu1 = new Student('张三', '男', 18, 01, '三班')
console.log(stu1)
stu1.study()
stu1.eat()
super关键字
// super 关键字 它在js中特用于!class的情况!
// console.log(super) err
// super关键字有点类似于this this==》指代某个对象!
// super也有指代的意思,也是指代某种东西!
// super的指代,或者使用的三种情况
// 1. cconstructor 构造函数中使用时 super 就是指代了 父类的constructor函数本身
// 2. 在子类的'普通'方法中(除静态方法外) super 指代的是 父类的 prototype属性指向的对象 Student extents Person ==》 super ==》 Person.prototype
// 3. 在子类的静态方法中, super 指代的是 父类 本身 Student extents Person super ==》 Person
// 类中有那些方法? 静态方法 static 私有方法 # 普通方法 无任何修饰
class Person {
static myname = 'Person'
constructor(name, sex, age) {
this.name = name
this.sex = sex
this.age = age
}
eat() {
console.log('eat....')
}
}
class Student extends Person {
constructor(name, sex, age, sid, clazz) {
// 调用一次 父类的 constructor
// 关键字 super
super(name, sex, age) // super代表的是父类的 constructor函数
this.sid = sid
this.clazz = clazz
}
study() {
console.log('上课中...')
// console.log(super) //注意: 使用super 不能查看super super.sss super()
// console.log(Person.prototype.eat === super.eat) // true
// super.eat()
}
// 定义一个私有方法
#mytest() {
//console.log(Person.prototype.eat === super.eat) // true Person.prototype === super
super.eat()
}
test() {
this.#mytest()
}
// 定义一个静态方法
static fun() {
console.log('fun...')
console.log(super.myname) // Person super === Person
}
}
// 1. cconstructor 构造函数中使用时 super 就是指代了 父类的constructor函数本身
let stu1 = new Student('张三', '男', 18, 01, '三班')
// 2. 在子类的'普通'方法中(除静态方法外) super 指代的是 父类的 prototype属性指向的对象 Student extents Person ==》 super ==》 Person.prototype
stu1.study()
stu1.test()
// 3. 在子类的静态方法中, super 指代的是 父类 本身 Student extents Person super ==》 Person
// console.log(Person.myname) super.myname ==> Person
Student.fun()
面向过程&面向对象编程思想
// 编程思想
// 面向过程:以过程为导向! step by step ‘一步一步的’
// 面向对象:以对象为导向! 面向对象进行编程! 主要是构建类! 一般用于比较复杂的抽象的问题!该思想更方便!
// 计算器 计算两个数据的 加减乘除:
// 面向过程
// let num1 = Number(prompt('请输入数字1:'))
// let num2 = Number(prompt('请输入数字2:'))
// let symbol = prompt('请输入运算符:+ - * /')
// switch (symbol) {
// case '+':
// alert(num1 + num2)
// break
// case '-':
// alert(num1 - num2)
// break
// case '*':
// alert(num1 * num2)
// break
// case '/':
// alert(num1 / num2)
// break
// default:
// break
// }
// 面向对象
// 计算器对象 属性: num1 num2
// 方法1: 运算两个数的值
// 方法2: 输入一个数
class Jsq {
num1
num2
symbol
// 如果不需要构建任何的实例对象的属性,constructor可以为空但是不能不写
constructor() {}
// 接受一个数
getNum() {
return Number(prompt('请输入一个数据:'))
}
// 接受一个符合
getSymbol() {
return prompt('运算符:')
}
// 运算两数之和
computer() {
let res
switch (this.symbol) {
case '+':
res = this.num1 + this.num2
break
case '-':
res = this.num1 - this.num2
break
case '*':
res = this.num1 * this.num2
break
case '/':
res = this.num1 / this.num2
break
default:
break
}
return res
}
}
let jsq = new Jsq()
console.log(jsq)
jsq.num1 = jsq.getNum()
jsq.num2 = jsq.getNum()
jsq.symbol = jsq.getSymbol()
let res = jsq.computer()
console.log(res)
面向对象-闹钟
<!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>
.clock {
text-align: center;
}
</style>
</head>
<body>
<div class="clock"></div>
<script>
// 面向对象- 闹钟 类
// 属性:时间节点... 时针 分针 秒针 颜色 大小 ....
// 方法: 开始 结束 实时倒计时更新 到点提醒 ....
//
class Clock {
// 闹钟的实例
// 那些属性是需要构造
// 颜色,大小(宽 、 高)、时间节点(终点日期)
// 时分秒三个属性,计数属性 不需要构造的
hours = 0
minutes = 0
seconds = 0
// 定时器编号
timer
constructor(color, width, height, endTime, elment) {
// endTime 介质日期的时间对象
this.endTime = endTime.getTime() //用户传入的时间对象节点所代表的时间戳
this.elment = elment
this.elment.style.width = width
this.elment.style.height = height
this.elment.style.lineHeight = height
this.elment.style.backgroundColor = color
}
// 闹钟开始计时
begin() {
// 初始化 闹钟的 时分秒
this.render()
// 利用JS引擎 创建一个定时器
this.timer = setInterval(() => {
this.render()
}, 1000)
}
// 闹钟结束
stop() {
// 清除的定时器
clearInterval(this.timer)
}
// 实时的更新 时 分 秒 实时倒计时 渲染时分秒 倒计时
render() {
// 获取系统
let date = new Date().getTime()
// 计算节点时间和当前系统时间之间的差值
let difference = this.endTime - date
// 将差值转换为闹钟的 时 分 秒
this.hours = Math.floor((difference / 1000 / 60 / 60) % 24)
this.minutes = Math.floor((difference / 1000 / 60) % 60)
this.seconds = Math.floor((difference / 1000) % 60)
this.elment.innerHTML = `${this.hours}时${this.minutes}分${this.seconds}秒`
if (this.hours === 0 && this.minutes === 0 && this.seconds === 0) {
this.stop()
}
}
// 判断用户的节点日期是否正确!待完善
}
// 获取clock 元素
let clock = document.querySelector('.clock')
// 实例化这个类
let clock1 = new Clock('red', '200px', '200px', new Date(2023, 1, 6, 12, 13, 0), clock)
// 闹钟 开始计时
clock1.begin()
clock1.stop()
</script>
</body>
</html>