目录
- 变量
- 变量的特点
- JavaScript中的数据类型
- 值类型和引用数据类型的存储方式
- 数据类型的转换
- 自增自减运算
- Json对象
- 运算符
- 自增、自减
- 三目运算符
- 流程控制结构
- 获取文档元素并修改其元素值
- 通过元素对象获取和修改元素的属性
- 元素对象的标签体属性
- 通过简单的点击事件修改元素的标签体内容
- 数组
- js获取页面元素的样式属性值
- 文档树
- 创建节点
- 添加,插入节点
- 替换节点
- 删除节点
- 查询操作
- 快速收集表单数据
- 数据实例对象自身的遍历方法
- 字符串操作
- BOM对象
- 执行上下文
- this关键字
- 严格模式
- 构造函数
- new关键字
- js垃圾回收机制
- 闭包(重点)
- 时间对象
- 数学函数
- elment元素offset&&client系列的属性
- 事件
- 阻止事件冒泡
- 阻止元素默认事件
- js对象的继承问题
- 显示原型和隐式原型属性
- 原型链
- 显示原型对象和隐式原型对象的区别
- 私有属性和私有方法
- 静态属性和静态方法
- 子类和父类之前的继承语法
- super关键字
- 面向过程&面向对象编程思想
变量
变量就是存放数据的一个容器 (盒子),变量所保存的数据本质是存储在计算机的内存中的! 内存是通过硬件内存条所产生一块虚拟空间!通常称为内存空间!
变量的特点
内存中数据存储的特点:1.读写速度快 2.临时数据的存储 3.内存的存储空间是比较小的
JavaScript中的数据类型
数据类型
// mdn 数据类型:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Data_structures#%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B
数据类型是什么?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 的一个原始数据类型,用来指代引用类型数据的空值
值类型和引用类型数据的区别
值类型:变量中直接存贮值本身
引用类型:变量中存储的是引用地址,而值是存在引用地址所指向的内存中的某个对应位置
值类型和引用数据类型的存储方式
值类型 、 引用类型
这两者的区别体现在哪里?
体现在内存中存储的方式不同!
// 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}
数据类型的转换
数据的类型转换:将某个数据的类型通过某种方式转换为另一种数据类型! 比如: number ==》 string
数据转换通过方式不同可以分为:强制转换、隐式转换
强制转换:人为的通过手段去改变一个数据的类型
隐式转换:没有人为的参与,是程序解析自动进行转换
强制转换:
Number(x)函数 该函数可以将其他的数据类型强制转换为Number类型的数据
console.log(typeof 100)
String ==》 Number
console.log(Number('123'), typeof Number('123'))
console.log(Number('abc'), typeof Number('abc')) // NaN是一种特殊的number值,该值表示无法正确转换时的替代!其类型也是Number not a number
console.log(Number('你好'), typeof Number('你好'))
console.log(Number('123a'), typeof Number('123a')) // NaN
console.log(Number('3.14'), typeof Number('3.14')) // 3.14
console.log(Number('-100'), typeof Number('-100'))
Boolean ==> Number
console.log(Number(true), typeof Number(true))
console.log(Number(false), typeof Number(false))
BigInt ==》 Number
console.log(Number(100n), typeof Number(100n))
Null ==> Number
console.log(Number(null), typeof Number(null)) // 0
Undefined ==》 Number
console.log(Number(undefined), typeof Number(undefined)) // NaN
Symbol ==> Number
console.log(Number(Symbol('100')), typeof Number(Symbol('100'))) // 无法转换
Object ==> Number
console.log(Number({}), typeof Number({})) // NaN
总结:NaN表示该类型无法找到对应的Number值与之匹配!Symbol类型无法被转换为Number
实际的开发中,常常将 string Boolean 转换为 Number
补充除了Number()函数可以强制转换其他数据为Number类型外,还有两种手段
全局函数: parseInt() parseFloat
parseInt() 将其他数据类型转换为number的整数值
console.log(parseInt('100'), typeof parseInt('100'))
console.log(parseInt('123a'), typeof parseInt('123a')) // 123
console.log(parseInt('3.14'), typeof parseInt('3.14')) // 3
console.log(parseInt(3.5))
console.log(parseInt('123.11a'), typeof parseInt('123.11a'))
parseFloat() 将其他数据类型转换为number的浮点数
console.log(parseFloat('100'), typeof parseFloat('100'))
console.log(parseFloat(200), typeof parseFloat(200))
console.log(parseFloat('3.14'), typeof parseFloat('3.14'))
console.log(parseFloat('123a'), typeof parseFloat('123a'))
console.log(parseFloat('123.11a'), typeof parseFloat('123.11a'))
---------------------------------------------------
String() 该函数是将其他类型强制转换为字符串类型
Number ==> String
console.log(String(100), typeof String(100))
console.log(String(3.14), typeof String(3.14))
console.log(String(-200), typeof String(-200))
BigInt ==> String
console.log(String(200n), typeof String(200n))
Boolean ==> String
console.log(String(true), typeof String(true)) // true ==> 'true'
console.log(String(false), typeof String(false))
null ==> String
console.log(String(null), typeof String(null))
undefinde ==> String
console.log(String(undefined), typeof String(undefined))
Symbol ==> String
console.log(String(Symbol('adbcdddf')), typeof String(Symbol('abcdddf')))
Object ==> String
console.log(String({}), typeof String({})) // '[object Object]' json对象转为字符串后,值固定为 '[object Object]'
console.log(String([1, 2, 3]), typeof String([1, 2, 3]))
---------------------------------------------------
Boolean() 该函数是将其他类型强制转换为布尔类型
Number ==》 Boolean
Number类型转换为Boolean时,除0,+0,-0,以外的值都转换为true
console.log(Boolean(100), typeof Boolean(100))
console.log(Boolean(-100), typeof Boolean(-100))
console.log(Boolean(3.14), typeof Boolean(3.14))
console.log(Boolean(0), typeof Boolean(0))
console.log(Boolean(-0), typeof Boolean(-0))
console.log(Boolean(+0), typeof Boolean(+0))
String ==》 Boolean
字符串类型在转换为布尔值时除 空字符''外的其他字符串都转换为true
console.log(Boolean('100'), typeof Boolean('100'))
console.log(Boolean('abc'), typeof Boolean('abc'))
console.log(Boolean('3.14'), typeof Boolean('3.14'))
console.log(Boolean('你好'), typeof Boolean('你好'))
console.log(Boolean(' '), typeof Boolean(' '))
console.log(Boolean(''), typeof Boolean(''))
BigInt ==》 Boolean
console.log(Boolean(100n), typeof Boolean(100n))
console.log(Boolean(-100n), typeof Boolean(-100n))
console.log(Boolean(0n), typeof Boolean(0n))
null ==》 Boolean
console.log(Boolean(null), typeof Boolean(null)) //false
undefined ==> Boolean
console.log(Boolean(undefined), typeof Boolean(undefined)) // false
Symbol ==> Boolean
console.log(Boolean(Symbol(100)), typeof Boolean(Symbol(100)))
Object ==> Boolean
console.log(Boolean({}), typeof Boolean({}))
console.log(Boolean({ name: 'zhagnsan' }), typeof Boolean({ name: 'zhangsan' }))
总结:js中的假值,假值就是通过强制转换或者隐式转换该数据为布尔类型后,其结果为false的数据称为假值!
js中的假值: false 、 0 、 -0 、 +0 、 null 、 undefined 、 ''
自增自减运算
自增、自减
// ++ 、 –
自增运算:
前自增、后自增 , 运算符都是 ++ 只是++的位置不同
自减运算:
前自减、后自减 , 运算符都是 -- 只是--的位置不同
自增,自减运算
运算规则: 将变量自身的值取出来+1或-1,然后重新赋值给变量!
let num = 50
num = num + 1
console.log(num)
自增操作
let num = 50
num++ 后自增 等价于 num = num +1 、 num+=1
++num 前自增 等价于 num = num +1 、 num+=1
console.log(num)
前自增和后自增的区别:
前自增,是先将数据进行+1,然后再参与其他的运算
后自增,是先利用原始数据参与其他的运算,然后再进行+1操作
Json对象
// json对象,花括号对象
// json对象的创建利用{}进行创建
// json对象中数据的存储采用键值对的方式, key:value ,其中key的数据类型必须是字符串,value可以是任何的合法数据类型!
// json对象中多个属性值使用逗号分隔
// 大多数时候,js允许省略key的引号或者双引号,省略的前提是属性名的命名符合标识符的命名规则
var obj1 = {
name: 'obj1',
'black-color': 'red',
a: true,
b: false,
c: null,
d: [1, 2, 3, 4],
f: {
x: 100,
},
} // console.log(obj1)
// 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数据类型!
变量:变量就是存放数据的一个容器
声明变量:
var:可以同时声明多个变量,还可以重复声明相同的变量
let:可以同时声明多个变量,但是不可以在同一作用域重复声明相同变量
const:声明常量变量且声明的常量不可以被修改,在同一作用域下不允许声明相同的变量
json对象的序列化和反序列化
json对象的序列化和反序列化
序列化:将一个合法的json对象,转换为一段标准的json格式的数据!
反序列化:将一段标准的json格式的数据,字符串转化为一个合法的json对象!
序列化:利用js提供的JSON对象上的方法进行操作 JSON.StringIfy
let obj = {
name:'张三',
age:18,
a:[1,2,3],
b:{
x:100,
y:100
}
}
var res = JSON.stringify(obj)
console.log(res,typeof res)
反序列化:利用js提供的JSON对象上的方法进行操作 JSON.parse()
var newobj = JSON.parse(res)
console.log(newobj , typeod newobj)
console.log(newobj.name,newobj.age)
运算符
js中的运算符分类:
- 算术运算符
- 赋值运算符
- 比较运算符
- 逻辑运算符
- 三元运算符
- 单目运算符
算术运算符
算术运算符: + 、 - 、 * 、 / 、%(模运算,取余)、**(幂运算)
复合运算符
复合赋值运算符:该运算符是 赋值运算符 与 算数运算符的结合书写!
注意:复合赋值运算符也具备赋值运算的功能!
+= 、 -= 、 /= 、 %= 、 **= 、*=
比较运算符
比较运算符:用于对两个数据进行数据的比较,其比较结果为布尔值!true 或 false
js中的比较运算符: > 、< 、 >= 、<=、 ==、 =、 != 、!
逻辑运算符
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中的逻辑与和逻辑或都是属于短路与,短路或!
逻辑或(短路或)
运算语法: 表达式1 || 表达式2 如果||运算两侧的数据类型不是布尔类型,则先进行隐式转换! Boolean()
或运算口诀: 全假为假,一真即真
console.log(false || false) // false
console.log(false || true) // true
console.log(true || true) // true
console.log(true || false) //true
自增、自减
// ++ 、 --
自增运算:
前自增、后自增 , 运算符都是 ++ 只是++的位置不同
自减运算:
前自减、后自减 , 运算符都是 -- 只是--的位置不同
自增,自减运算
运算规则: 将变量自身的值取出来+1或-1,然后重新赋值给变量!
let num = 50
num = num + 1
console.log(num)
自增操作
let num = 50
num++ 后自增 等价于 num = num +1 、 num+=1
++num 前自增 等价于 num = num +1 、 num+=1
console.log(num)
前自增和后自增的区别:
前自增,是先将数据进行+1,然后再参与其他的运算
后自增,是先利用原始数据参与其他的运算,然后再进行+1操作
三目运算符
语法规则: 表达式?结果1:结果2
运算流程:计算表达式结果,如果表达式为真,则将结果1的数据进行返回,否则返回结果2的数据
let res = 100 < 50 ? 100 : 200
let num = false ? 10 + 1 : 20 + 1
console.log(num)
流程控制结构
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——————')
多分支语句
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——————')
条件分支语句 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——————')
循环结构
js的循环结构
循环:重复的执行一段相同的代码
js中提供了以下几个循环语句
while语句 do…while语句 for语句
while循环
while循环
语法:
while (表达式) {
循环体
}
while循环的注意事项:
1.必须设置循环控制变量
2.必须为循环控制变量赋初始值
3.每一次的循环体结束前应该更新循环控制变量
执行流程,首先判断表达式的true或者false,如果为true则执行循环体的代码,否则结束while循环
如果判断为true则执行循环体的代码,当循环体代码执行完毕时,再次判断表达式的真假!重复以上操作!直到表达式为false,退出while语句
while循环实现
1.设置循环控制变量
let count = 1 // 2.设置初始值
while (count <= 5) {
console.log('hello world!')
// 3. 更新循环控制变量
count++
}
console.log('end—————')
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循环
let count = 1
while(count<=5) {
console.log('hello world!')
count++
}
for (let count = 1; count <= 5; count++) {
console.log('hello world!')
}
for (let count = 1; count <= 5; count++) {
console.log('hello world!')
}
练习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…
continue和break关键字
这两个关键字都可以让循环提前结束
break关键字:直接结束当前包含break的循环语句进入下一个步骤
continue:该关键字只结束该循环的本次内容,后续的循环继续执行
获取文档元素并修改其元素值
浏览器为程序员提供了一个接口!
该接口可以访问页面中的所有元素节点!
该接口是一个对象!浏览器提供! 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')
通过元素对象获取和修改元素的属性
// 获取 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
可以使用Array.isArray()来判断一个变量是否为数组
修改数组元素的值
修改数组中对应元素的值 利用 赋值运算
let arr = [100, 200, 300, 'hello']
console.log(arr)
arr[0] = 500
console.log(arr)
数组的常见操作
数组的常见操作
所有的数组实例对象,都来自于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 = ['a', 'b', 'c', 'd', 'f']
// 需求遍历 arr
// 利用for循环来进行遍历 最传统的方式
for (let i = 0; i < arr.length; i++) {
// console.log(i)
console.log(arr[i])
}
对数组进行倒置操作
倒置操作: [‘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'
文档树
文档树
浏览器会将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)
删除节点
<body>
<ul>
<li class="first-li">旧的li</li>
<li>li</li>
<li>li</li>
<li>li</li>
</ul>
</body>
<script>
删除操作
方式一:元素自删除!
let firstli = document.querySelector('.first-li')
firstli.remove() // 元素自我删除
方式二: 利用父节点进行删除指定的子元素节点
let ul = document.querySelector('ul')
ul.removeChild(firstli)
查询操作
<body>
<ul>
<li class="first-li">旧的li</li>
<li>li</li>
<li>li</li>
<li>li</li>
</ul>
</body>
<script>
// 查询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)
</script>
快速收集表单数据
1.先获取元素值
2.如果需要拿到的元素不止一个,那就先遍历所需要的元素,以input为例,先拿到所有的input元素,然后将其所有元素遍历,可以通过input元素的value值来进行数据的收集
通过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'))
})
通过数组渲染表格
<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循环遍历,这里就不详细说了
foreach方法
let arr = [100, 200, 300, 400]
// forEach方法进行遍历数组
// forEach方法可以实现数组的遍历操作!对数组中每一个元素进行访问
// 每访问一个元素就执行一次callback函数 , forEach方法没有返回值
arr.forEach((el, index, myarr) => {
// el : 代表当前正在访问的数组元素
// index:代表当前正在访问的元素下标
// myarr:操作数组本身 一般情况下会省略myarr参数
// console.log(el, index, myarr)
// console.log(myarr === arr)
})
// forEach和for循环的区别
// forEach方法相对于for循环来说,更方便一些!
// forEach它不允许打断,数组元素有多少个,callback就一定会执行多少次
// for循环可以中途退出
every方法
let arr = [100, 200, 300, 400]
// every和forEach基本上是一样的!
// every方法同样可以遍历数组,但是允许中途退出!
// every方法会根据callback函数每次执行后的返回值进行判断,如果为true 则继续遍历操作,如果为false 则退出遍历操作!
// every具备返回值,返回值的类型是布尔值!
// let res = arr.every((el, index, myarr) => {
// return el >= 100
// })
// console.log(res)
// every方法的真正作用是,判断某一个数组中是否所有的元素都满足相应的要求!满足则返回 true 只要有一个不满足就返回false
// 需求:判断一个数组中是否每一个元素都是偶数
// let myarr = [2, 2, 4, 8, 16, 10]
// let res = myarr.every((el) => {
// return el % 2 == 0
// })
// if (res) {
// console.log('该数组全部是偶数')
// } else {
// console.log('该数组中至少有一个元素不是偶数')
// }
some方法
let arr = [1, 2, 301, 401]
// some方法和every方法是相反的
// some方法是遍历一个数组的所有元素,如果有一个元素满足条件,sonme就返回 true 否则返回false
// some方法在遍历元素中,每遍历一个元素执行一次回调函数,如果回调函数返回 false 则继续遍历! 直到遍历结束或返回true
// arr.some((el, index, myarr) => {
// console.log(el)
// return true
// })
// 需求: 判断一个数组中是否至少有一个元素是偶数
// let res = arr.some((el) => {
// console.log(666)
// return el % 2 == 0
// })
// if (res) {
// console.log('符合要求')
// } else {
// console.log('不符合要求')
// }
map方法
let arr = [100, 200, 300, 400]
// map方法 它会返回一个新的数组
// 新数组从每一次执行callback的返回值来,每一次callback返回值都会放到该数组中!
// let res = arr.map((el, index, myarr) => {
// console.log(el, index, myarr)
// return 100
// })
// console.log(res)
// 需求:我想将arr数组中的每一个元素在原有的基础上增加一倍!
// let res = arr.map((el) => {
// return el * 2
// })
// console.log(res)
// map实现数组的浅拷贝
// let res = arr.map((el) => {
// return el
// })
// console.log(res === arr)
filter方法
// 过滤器 filter方法 也会返回一个数组
// 每一次callback函数执行后的函数值 如果true 则保留当前的元素到新数组中,如果是false 则继续下一次遍历
// let arr = [1, 2, 3, 4]
// // 需求:筛选出arr数组中的所有偶数 组成一个新的数组
// let res = arr.filter((el) => {
// return el % 2 == 0
// })
// console.log(res)
find方法
// find 从数组中查找符合条件第一个元素并返回该元素,如果遍历完整个数组都没有找到符合添加的元素则返回 undefined
// let arr = ['张三', '李四', '王五', '李四']
// // 需求: 从arr数组中查询是否存在 一个元素值为 '李四' 存在则返回该元素
// let res = arr.find((el) => {
// console.log(666)
// return el === '李四xxxx'
// })
// console.log(res)
findIndex方法
// findIndex 从数组中查找符合条件第一个元素并返回该元素的下标值,如果遍历完整个数组都没有找到符合添加的元素则返回 -1
let arr = ['张三', '王五', '李四']
// 需求: 从arr数组中查询是否存在 一个元素值为 '李四' 存在则返回该元素
let res = arr.findIndex((el) => {
return el === '李四xxxxxx'
})
console.log(res)
字符串操作
字符串基础
// 字符串的基础内容
// 设置字符串
let str1 = 'hello world!'
// let str2 = 'hello world!'
// let str3 = `hello world!`
// 读取字符串
console.log(str1)
// 将字符串看作是数组的形式,进行访问字符串中单个字符
// 利用下标值,访问单个字符串的内容
console.log(str1[0])
console.log(str1[1])
console.log(str1[2])
// 字符串的其他操作! 字符串
console.log(typeof str1) // string
// 万物皆对象
// Object类型的对象 才具备属性和方法
// length属性 查看字符串的长度!
console.log(str1.length)
// 从常规来说,基本数据类型不是对象,是无法拥有属性和方法的!也不能像操作对象那样操作普通数据!
// 但是在js中一个工具,js引擎在执行非对象类型的数据时,如果该数据类型并不是Object!那么js会进行包装!把它包装成一个Object类型!
// console.log(Object(str1))
// console.log(Object(100))
// console.log(Object(true))
charAt方法
let str = 'hello world!'
// charAt方法 是通过指定的下标进行访问对应的字符 类似于 str[0]
let res = str.charAt(0) // 等价于 str[0]
console.log(res)
split方法
let str = 'hello world!'
// split方法 通过指定的字符将字符串分割成一个字符数组!
let res = str.split('')
console.log(res)
concat方法
let str1 = 'hello'
let str2 = 'world!'
// concat是将多个字符串进行拼接 等价于 +
let str3 = str1.concat(str2)
console.log(str3)
includes方法
let str = 'abcdefg'
// includes去字符串中查询是否存在一个指定的字符!存在则返回 true 不存在 返回 false
let res = str.includes('a')
console.log(res)
indexOf方法
let str = 'abcdefg'
// indexOf去字符串中查询是否存在一个指定的字符!存在则返回 对应的下标值 不存在 返回 -1
// 从左往右查找第一个匹配的字符下标
let res = str.indexOf('axxxxx')
console.log(res)
lastIndexOf方法
let str = 'abcdefg'
// lastIndexOf去字符串中查询是否存在一个指定的字符!存在则返回 对应的下标值 不存在 返回 -1
// 从右往左查找第一个匹配的字符下标
let res = str.lastIndexOf('g')
console.log(res)
trim方法
let str = ' hello world! '
console.log(str)
// trim 去除字符串前后的空格
let res = str.trim()
console.log(res)
trimStart方法
let str = ' hello world! '
console.log(str)
// trimStart 去除字符串前面的空格
let res = str.trimStart()
console.log(res)
trimEnd方法
let str = ' hello world! '
console.log(str)
// trimEnd 去除字符串后面的空格
let res = str.trimEnd()
console.log(res)
toUpperCase方法
let str = 'abcdefgABCDN'
// toUpperCase该方法将字符串中所有的小写字母转换为大写字母
let res = str.toUpperCase()
console.log(res)
toLowerCase方法
let str = 'abcdefgABCDN'
// toLowerCase该方法将字符串中所有的大写字母转换为小写字母
let res = str.toLowerCase()
console.log(res)
substring方法
let str = 'hello world!'
// substring(开始下标,结束下标) 方法是对字符串进行截取
// 注意:截取区间是 左闭右开的区间
// let res = str.substring(0, 5)
// let res = str.substring(2) //如果省略结束下标,则从指定位置截取到字符串末尾!
// 如果 indexStart 等于 indexEnd,substring 返回一个空字符串。
// 如果省略 indexEnd,substring 提取字符一直到字符串末尾。
// 如果任一参数小于 0 或为 NaN,则被当作 0。
// 如果任一参数大于 stringName.length,则被当作 stringName.length。
// 如果 indexStart 大于 indexEnd,则 substring 的执行效果就像两个参数调换了一样。见下面的例子。
console.log(res)
startsWith方法
let str = 'hello world!'
// startsWith 方法 判断该字符串是否以指定的字符串进行开头
let res = str.startsWith('hello')
console.log(res)
endsWith方法
let str = 'hello world!'
// endsWith 方法 判断该字符串是否以指定的字符串进行结尾
let res = str.endsWith('!')
console.log(res)
replace方法
let str = 'hello world!'
// replace 方法将指定的字符替换为其他字符
let res = str.replace('hello', 'xxxx')
console.log(res)
BOM对象
window
BOM (浏览器对象)对象 ==》 代表整个浏览器
浏览器环境中,为js提供了两个对象!这两个对象是浏览器提供的,也称为宿主对象!
DOM (文档对象) ===》 文档树
BOM下的具体的对象!
window对象 BOM的核心对象 windonw指向的是 浏览器的窗口!
windo对象除了指向浏览器窗口,它还代表着js在浏览器环境下的全局对象!也称为顶层对象!
console.log(window)
window作为顶层对象,它的作用!在全局环境下所声明的全局var变量或者函数都是作为window对象的属性存在!
var num = 200
console.log(num)
console.log(window.num)
function fun() {
console.log(666)
}
fun()
window.fun()
window.alert()
window.prompt()
console.log(window)
let num = 500
console.log(num)
console.log(window.num) // let和const所声明的变量 不能作为window对象的属性存在!
location
let data = 'hello world!'
let btn = document.querySelector('button')
btn.addEventListener('click', () => {
// location.href = 'https://www.baidu.com'
// location.replace('https://www.bilibili.com')
// location.reload()
location.href = './demo.html' + '?' + data
console.log(location.search)
})
// location 代表浏览器地址栏
// 文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Location
// 跳转网页
// location.href = 'https://www.baidu.com'
// 跳转网页不计入历史,更新地址栏,不计入历史操作
// location.replace('https://www.bilibili.com')
// 刷新页面
// location.reload()
// 地址栏参数 ?后的数据 key=value 键值对的形式
// location.search
// console.log(location.search, location)
history
let btns = document.querySelectorAll('button')
btns[0].addEventListener('click', () => {
history.forward() // 前进
})
btns[1].addEventListener('click', () => {
console.log(666)
})
// history 浏览器浏览记录(历史记录)
// 文档:https://developer.mozilla.org/zh-CN/docs/Web/API/History
// 前进
// history.forward()
// 后退
// history.back()
// 转到指定位置
// history.go(delta)
// history.go(1) 等价于 history.forward()
// history.go(-1) 等价于 history.back()
navigation
// navigator 用于查看设备信息,查询当前浏览器的信息、版本、名称等
// 文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator
console.log(navigator)
执行上下文
// 执行上下文环境: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()
this关键字指向练习
第一题 01
var o = {
a: 10,
b: {
a: 12,
fn: function () {
console.log(this.a)
console.log(this)
},
},
}
o.b.fn()
第一题 02
var o = {
a: 10,
b: {
fn: function () {
console.log(a)
console.log(this)
},
},
}
o.b.fn()
第二题
var o = {
a: 10,
b: {
a: 12,
fn: function () {
console.log(this.a)
console.log(this)
},
},
}
var j = o.b.fn
// j == > function(){}
j()
第三题
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
// this ==> point {}
this.x = this.x + x;
this.y = this.y + y;
console.log(this.x);
console.log(this.y);
}
};
point.moveTo(1, 1)
4、第四题
function someFun(x) {
// this ==> window
this.x = x // window.x
}
someFun(5)
console.log(x) //
5、第五题
var point = {
x: 0,
y: 0,
moveTo: function (x, y) {
// var x = 1
// var y = 1
// this ==》 point
var moveX = function (x) {
// var x = 1
// this ==》 window
this.x = x
}
var moveY = function (y) {
this.y = y
}
moveX(x) // 1 moveX 什么形式 函数 function函数 中this ==》 window
moveY(y) // 1
},
}
point.moveTo(1, 1) // moveTo 方法形式执行, 该方法中的this 是 point{}
console.log(point.x) //
console.log(point.y) //
console.log(x, y) //
第六题
var point = {
x: 0,
y: 0,
moveTo: function (x, y) {
// var x = 1
// var y = 1
// this ==》 point
this.x = x // point.x = 1
console.log(this.x) //
console.log(this) //
var moveX = function (x) {
this.x = x // window.x = 1
}
var moveY = function (y) {
this.y = y // window.y = 1
}
moveX(x) //
moveY(y)
},
}
point.moveTo(1, 1) // moveTo() 是以方法形式调用 this==》 找他的调用者
console.log(point.x) //
console.log(point.y) //
console.log(x) //
console.log(y) //
第七题
var point = {
x: 0,
y: 0,
moveTo: function (x, y) {
// var x = 1
// var y = 1
var that = this // that = point
var moveX = function (x) {
// var x = 1
that.x = x //
this.x = x //
}
var moveY = function (y) {
that.y = y //
this.y = y //
}
moveX(x) // moveX 函数 this ==》 window
moveY(y)
},
}
point.moveTo(1, 1) // moveTo 方法 调用者 point 对象 this ===》 point
console.log(point.x) //
console.log(point.y) //
console.log(x) //
console.log(y) //
第八题
var point = {
x: 0,
y: 0,
moveTo: {
moveX: function (x) {
// var x = 1
console.log(this) //
this.x = x //
},
moveY: function (y) {
// var y = 1
this.y = y //
},
},
}
point.moveTo.moveX(1) // moveX 方法形式调用 this==》 调用者 moveTO {}
point.moveTo.moveY(1) // moveY 方法形式调用 this==》 调用者 moveTO {}
console.log(point.moveTo) //
console.log(point.x) //
console.log(point.y) //
console.log(window.x) //
console.log(y) //
第九题
var x = 10
var y = 20
// var 声明的变量 会被挂载到 widow对象上作为window的属性存在
var obj = {
x: 0,
y: 0,
fun: () => {
// 因为该箭头函数没有自己的this,它永远绑定的是被创建时,当时执行环境下的this,永不更改!
// this ==》 window
this.x = this.x + 1
this.y = this.y + 1
},
}
obj.fun()
console.log(x)
console.log(y)
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)()
严格模式
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'
-
不允许赋值只读属性
-
'use strict' const obj = {} Object.defineProperty(obj, 'x', { value: 0, writable: false }) obj.x = 3.14
-
'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
-
function fn() { console.log(this) // => undefined }
-
构造函数
// 构造函数:构造函数也是函数!构造函数的本义是用于构造一个实例对象!并不是像普通函数一样为了实现某种功能!
// 任何函数都可以作为构造函数使用!前提是 它是否被 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就不要写了!
function Person(name,age,sex){
// console.log(this)
this.name = name
this.age = age
this.sex = sex
return {
x:100
}
}
var p1 = new Person('张三',20,'男')
console.log(p1)
new关键字
new关键字是配合构造函数使用:
new关键字,做了几件事情:
1.new关键字会创建一个该构造函数的实例对象,一开始是空的{}
2.new关键字会将刚才创建的实例对象的__proto__属性指向为 构造函数所保存的 prototype指向的对象
3.new关键字会将构造函数中的this 指向为 该实例对象
4.最终返回这个 实例对象
js垃圾回收机制
垃圾回收:JavaScript程序在运行的过程中,随着运行时间的增加,那么会相应的产生一些垃圾数据,垃圾回收机制主要是
定时的去清理这些垃圾数据,避免内存溢出、泄露导致程序崩溃!
内存的溢出:
内存的泄露:
注意:垃圾回收这个动作不需要人为的去管控,它是由js引擎垃圾回收的模块负责
如何定义垃圾:
- 标记清除:假设所有的变量或者函数等其他数据,一开始就认为他们不是垃圾!当他们产生了某种变化后,就会被打上标记,标记为垃圾
- 引用计数:当引用型数据,没有再被任何引用时,引用链条为0的时候!就自动判定为垃圾数据
正常情况下:
- 全局作用域下的变量、函数在程序执行完毕后才会销毁
- 局部作用域下的变量、函数,当该局部作用域执行完了!结束后,就销毁对应的变量以及函数
- 引用数据当引用链条数量为0的时候,也会被销毁
小提示:
垃圾回收机制并不是JavaScript语言独有,很多编程语言都具备
- java、python、JavaScript
- c c++ 人为的控制,人为的定期去是释放内存
闭包(重点)
闭包:把一些数据进行封装!包裹!形成一个独立的空间,该空间只会被能访问到该空间的‘人’使用
如何才会产生一个闭包:
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提供的一种针对处理时间相关的内容的对象!
// 比如:一个商品的打折时间! 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())
elment元素offset&&client系列的属性
* {
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
事件
方式一
<button onclick="test(100)">按钮</button> -->
<!-- 方式二 -->
<button>按钮</button>
方式三
<button>按钮</button>
<script>
事件:某个事情,特殊的一种情况!
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('监听器方式')
})
</script>
事件的解绑
<!-- 方式一: -->
<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>
为一个元素绑定多个相同的事件
事件属性 和 事件监听器的区别
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)
事件监听的方式可以为同一个元素绑定多个相同类型的事件,并且指定不同的处理方式
事件的分类
// 参考: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>
事件对象
// 事件对象:一个事件被触发后!浏览器对应的会自动产生一个事件对象!并且该事件对象是具备类型的!
// 鼠标事件、键盘事件、资源事件....
// 事件对象的作用:事件对象上存放了一些与该事件产生时的一些数据或者方法!
// 事件对象如何使用?
// 事件对象在事件函数被执行时,浏览器会自动的向该事件函数传入对应的事件对象!只需要利用一个形参变量来接受即可!
// 一般这个形参变量,命名为: event ==> ev
// 注意:不同类型的事件对象,所保存的数据的不一样的!有些属性是任何事件对象都具备的,比如: type
// 也有很多的属性是该事件对象所独有的!
// 事件函数调用执行时,一般不会传入其他的参数!
// 因为事件函数的第一个实参是传入的事件对象!
document.addEventListener('click', (event) => {
console.log(event)
})
document.addEventListener('keydown', (event) => {
console.log(event)
})
</script>
鼠标事件对象常用属性
<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
})
事件执行机制—冒泡
<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>
事件执行机制—捕获
<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>
event对象的target¤tTarget属性的区别
<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>
事件的代理和委托
<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>
阻止js代码触发事件
<body>
<button class="btn">按钮</button>
<script>
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)
</script>
阻止事件冒泡
<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>
阻止元素默认事件
<form action="">
<button>提交</button>
</form>
<!-- button按钮在表单中 默认就存在一个 提交事件 -->
<script>
let btn = document.querySelector('button')
btn.addEventListener('click', (ev) => {
// 阻止默认事件的发生
ev.preventDefault()
console.log(6666)
})
</script>
# 鼠标移入移出事件
```javascript
<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>
事件的捕获与冒泡过程
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()
</script>
显示原型和隐式原型属性
// 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中的继承是利用了隐式原型对象
// 以及原型链的概念,最终实现了实例对同一构造函数上的方法或者属性的继承!
</script>
原型链
实例对象身上__proto__ 存储的是什么数据类型? Object
原型链
每一个实例对象上都具备 __proto__ 原型对象
当一个对象在自身上找不到对应的属性或者方法时,会沿着__proto__原型对象身上去寻找! obj {}
如果往上一级的__proto__身上还是找不到想要的属性或者方法 obj.__proto__
那么它会继续沿着当前这一级__proto__继续寻找! obj.__proto__.__proto__
.... obj.__proto__.__proto__.__proto__
沿着原型链最终找到 null 就结束! 如果已经访问到null 都还没有找到想要的属性或者方法 则放回 undefined
以上描述寻找的过程就称为 原型链!
显示原型对象和隐式原型对象的区别
<script>
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
</script>
静态属性和静态方法
<script>
// 静态属性和静态方法,指的是该属性和方法只能由类本身进行调用!
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()
</script>
子类和父类之前的继承语法
// 定义一个类 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)