JavaScript
JS是一种解释性的脚本语言,执行的时候才会去编译,弱类型(不是明确规定数值类型),可移植性强
WebApi
DOM:文档对象模型
BOM:浏览器对象
api是封装好的一种工具,接口,可以通过调用api实现某种功能
//交互弹窗
let a = confim('你确定吗')
//确定返回true,取消返回false
//消息弹窗
let b = alert('你不对')
//接收数据
let c =prompt('输入姓名')
// prompt用于接受用户输入的数据!点击确定,返回就是用户输入的数据,点击取消,返回就是null
文档树
文档树:它是一个浏览器解析了html文档,根据文档渲染出对应的标签,并且以文档数的形式存在!
BOM
浏览器对象模型
window
window它代表了当前整个浏览器
window对象也是js执行环境的顶层的对象
location(浏览器地址栏)
代表浏览器地址栏
location.href = 'www.balabala.com'
location.replace('balabala.com')
共同点:都可以更改地址栏的值,并且跳转到指定的页面
不同点:href赋值后的新数据,会被计入到历史记录中 ,repalce不会记录到历史记录中
history
history是BOM对象之一
它代表浏览器的历史记录,就表示前进后后退按钮
history.go(1)==history.forward()
//前进到下一个历史页面
history.back()
//返回到上一个历史页面
localStorage(永久存储数据到浏览器中)
localStorage.setItem('name','张三')
localStorage['name']='张三'
//name:张三,键值对的形式存储到本地
//如果存储数据时对象形式,需要序列化才能进行存储
localStorage.setItem('arr', JSON.stringify(arr))
//拿数据是也要返序列化才能正常读取
JSON.parse(localStorage.getItem(arr))
sessionStorage(临时存储,窗口关闭即消失)
这个是临时存储,页面刷新保存的数据就会消失
navigator(了解)
查询当前的设备信息
DOM
document表示文档(一个网页就是一个文档)
element表示元素
常见获取节点方法
document.getElementById('box');对象
document.querSelector('.class/#id');对象
document.querSelectorAll('.class/#id');
document.getElementsByClassName('class');伪数组
document.getElementsByTagName('input');//符合这个标签的伪数组
修改标签体
//data是获取的节点
data.innerHTML
data.innerText
JS中设置元素样式
==toggle开关==
如果该元素存在对应的class则移除它,如果不存在则添加它
box.classList.toggle('类名')//可通过此操作,开关样式
添加元素样式
box.classList.add('box1','box2'...)
移除元素样式
box.classList.remove('box1','box2'...)
节点操作
创建节点
document.createElement('div')
let di = document.createElement('div')
这只是创建,节点还没有添加到文档树上
添加/插入节点
data.appendChild('div'),返回插入的元素,只能插一个
append("div"),无返回值,可以插入多个
parenElemnt.appendChild('div')
parenElemnt是父节点,此方法只能用于在父节点中插入子节点,并且是==在父元素的末尾添加==
inserBefore(新节点,子节点),在节点之前插入
//inserBefore,在节点之前插入
let father = document.querySelector('.father')
let son =document.querySelector('.son')
let div = document.createElement('div')
father.inserBefore(div,son)//将新创建的div节点,插入到son节点的前面
father.inserBefore(div,null)//将父元素插入到末尾,等价于appendChild
删除节点
data.remove()
let box = document.querySelector('.box')
box.remove()
//自我删除
father.removeChild(son)
let father = document.querySelector('.father')
let son =document.querySelector('.son')
fathrt.removeChild(son)
//删除父节点里的子节点
替换节点
father.replaceChild(新节点, 被替换的节点)
一次只能替换一个节点
let span1 = document.createElement('span')//创建新节点
let box = document.querySelector('.box')//获取被替换的节点
let father=document.querySelector('.father')//获取父节点
father.replaceChild(span1,box)//替换
father.replaceChildren(新节点, 被替换的节点)
father.replaceChildren(span1,span2)//可以接收多个
查询节点
father.children[下标]
let ul = document.querySelector('ul')
ul.children[0]
ul.children[1]
通过某个子元素,去查询该元素的父节点元素
son.parentElement
let li2 = document.getElementById('li2')
li2.parentElement//父节点
li2.parentElement.parentElement//爷爷节点
表单form
表单里的都是属性,所以都是通过.属性=‘’某某‘’来操作元素的
表单的具体属性
表格的增删改查(重点)
循环
for循环
for(let i=0;i<2;i++){}
for...in循环
for(变量 in 对象|数组){}
//如果是对象,则变量就是key
//如果是数组,则变量就是索引
for...of循环
主要用于去遍历可迭代的对象! Array Map Set
不可以去遍历json对象!因为json对象是不可迭代的
解释:不能遍历对象
for(let item of arr){}
//item 表示数组里的元素本身
数组(重点)
数组常用方法
arr.push()
尾部添加,无返回值
arr.pop()
尾部删除,==返回被删除的那个元素==
arr.unshift()
头部添加,无返回值
arr.shift()
头部删除,==返会被删除的那个元素==
arr.splice()
删除指定位置,并用新元素替换或者插入
arr.splice(指定下标,删除几个,插入新的元素)
arr.splice(0,1,a)//在下标0的位置上删除一个(本身),替换成a
arr.concat()返回新数组
拼接数组,并==返回一个新的数组==
arr.concat(数组,字符传等等)
arr.concat([1,2,3],[4,5])
//结果是[1,2,3,4,5]
arr.join()
用指定字符连接数组成员并==返回拼接好的字符串==
let arr=[1,2,3]
let b=arr.join('+')
console.log(b);//结果是1+2+3
arr.includes()
判断是否包含某成员,返回true和false
注意:它是用===来判断的
arr.indexOf()
查找指定元素索引,找到返回下标,没找到返回-1
==存在多个指定目标返回第一个找到的下标==
arr.LastIndexOf()
查询最后一个目标成员的索引,返回下标,没找到返回-1
存在多个时候,返回最后一个的下标(倒数第一个)
arr.slice()返回新数组
数组切片,左闭右开,==返回一个新数组==
从下标开始往后切片
let a=[1,2,3,4]
arr.slice(1,2)//结果是[2,3]
arr.reverse()
反转数组中的元素
let a =[1,2,3,4]
a.reverse()
console.log(a)
//结果为[4,3,2,1]
小技巧
arr.concat([]),可以通过去拼接空数组,实现深拷贝数组
arr.slice(0),从下标0开始往后切片,返回新的数组,实现深拷贝
arr.map(),映射出一个新数组,返回值为新数组,实现深拷贝
查询该数据是否唯一,可以通过查询第一个下标(indexOf)和最后一个下标
(LastIndexOf)是否相同,相同就是唯一
数组的常用迭代
arr.forEach()
遍历数组,相当于for 循环,无返回值
无法中途停止,一定会遍历每个元素
arr.forEach(function(el,index,arr){})
//el 元素本身
//index 下标
// arr 数组本身
arr.every() 返回布尔值
遍历数组,返回布尔值(true/false),正常结束返回true,非正常结束返回false
可中途跳出循环
let a=arr,every(function(el,index){
return false;//遇见false直接结束遍历
})
console.log(a)//结果是false,因为没有遍历完整就结束了
arr.map()返回新数组
映射数组到一个新数组中,可以理解为复制
返回值为一个新的投影数组,可以用来深拷贝数组
let a=[1,2]
let b=a.map(function(el,index){
return el+1
})
console.log(b)//结果为[2,3]
arr.filter()返回新数组
过滤,过滤后添加到新数组中,return true 保存,return false舍弃
返回新的数组,默认return true,可以深拷贝数组
let a= [1,2,3,4]
let b= a.filter(function(el){
if(el>2){return true}
})
console,log(b)//结果为[3,4]
arr.find()返回找到的第一个
查找
返回值为成功匹配的第一个元素,找到第一个符合条件的就停止遍历
let find= arr.find(function(el){
if (el.name=="张三"){
return ture
}
return false
})
//查找名为张三的人,找到后返回它的信息
arr.findIndex()返回索引
查找对应成员,返回对应成员的索引值
arr.some()返回布尔值
判断是否至少有一个满足你的要求成员,返回布尔值,有就true
注意:every是每一个都满足才会返回true
arr.sort()
数组排序,如果不传参,它会默认转换成编码格式进行排序,必须传参
el1-el2,前-后升序。el2-el1,后-前降序
let arr=[1,2,5,6]
arr.sort(function(el1,el2){
return el1-el2//升序
//return el2-el1, 降序
})
arr.reduce()
统计。。
let stu = [{ id: 0, age: 16 }, { id: 1, age: 20 }, { id: 2, age: 30 }, { id: 3, age: 30 }]
let b = stu.reduce(function (p, c) {
return p + c.age
}, 0)//这个零是给p的初始值
console.log(b);//结果为96
------------------------
let arr = [2,3,4,5]
let b = arr.reduce((p,n)=>{return p + n})
//b的值为14
//p为上一次返回的结果,n为下一次需要添加的数
-------------------------
let arr =[58,49,70,100,24]
//统计不及格人数
arr.reduce((p,n)=>{
//这里使用p表示不及格人数,设置默认为0个人
//n表示下一次要统计的数组成员(就是下一个数组成员)
if(n<60){p++}
return p
},0)
//需要统计什么,p就设置成什么
理解:reduce就是遍历数组时,p有初始值则n是0号成员,
p无初始值,则p是0号成员,这样开始遍历
函数
1.特点
方便,复用率高,能减少代码冗余
函数是一种Object类型数据!typeof==>function
它是引用型数据,它的==数据存放在堆空间中==
2.声明方式
function fun(){
//函数体
}
// function关键字直接声明方式
let fun2= function(){} //匿名声明方式
注意:函数在创建时不会执行里面的语句,只有被调用的时候才会执行
3.形参和实参
function add(a,b){
//return a+b;
}
add(10,100);
a,b就是形参。10和100就是实参
注意:函数传参时,参数顺序一致,参数个数一致,参数类型一致
4.函数返回值
返回值由return后面的语句决定
如果函数中省略了return,那么函数默认返回undefined,假值(false)
return有中断函数执行的功能
function(){
return
console.log(100)//这句不会被执行
}
函数其他类型
2.构造函数
let arr=new Array(1,2,3)
通过new 关键字调用的函数叫构造函数
3.立即执行函数
(function a(){})()//立即执行,相当于自己调用自己
4.箭头函数
let fun=()=>{}
fun();
箭头函数特点:
当形参个数为1个时候小括号可以省略
let fun= x=>{}
当大括号里只有一条语句时,大括号可以省略
let fun = ()=>console.log(6)
5.arguments
在function函数内部,隐式声明了一个arguments的变量
箭头函数里没有这个
它是一个伪数组,
作用:
- 接收函数所有实参
- 对匿名函数的递归调用
arguments.callee();//调用函数本身
function(){
//没有名字无法在里面调用它本身
arguments.callee();//调用本身
//arguments.callee===function(){}
}
6.值传递
let a=10,b=3
a=b,a的结果为3,值传递是直接存储在栈当中的
在进行赋值操作的时候就是真正的赋值
引用数据传递
传递数据存储的地址 ,
例如 let a={num:10},这个==对象在栈当中存储的是地址==,
==内容在堆当中==,如果进行赋值操作就是相当与把地址进行赋值
a=b,b.num改变,a.num也会跟着改变,因为他们指向同一地址。
7.作用域
定义:变量,函数的作用范围
作用域分三类:
1.全局作用域:==在块,函数之外声明的变量==,最上层的作用域,都能使用
let a = 100
2.函数作用域:==在函数体内部声明的变量或者函数==,只能在函数内部使用。
function(b,c){
let a = 10
}//这个a在外部无法访问
- 在函数作用域以外的地方是无法访问函数内部变量或者其他函数
- 函数的形参是在函数内部定义的,同样外部无法访问
- 函数作用域在函数执行完成后就会直接关闭,他只在函数执行的时候产生,所以无法访问
3.块级作用域:==在{}内用let或者const声明的变量==,只在{}里使用
{ let a = 10}
console.log(a)//这个a无法访问
- ES6之前不存在块级作用域
- 块级作用域必须是let和const在{}中声明
注意:变量未声明直接赋值,它会直接被定义为全局变量
8.作用域链
定义:沿着作用域的一个层级关系,向上去寻找其他的作用域变量
预解析
定义:在js代码真正执行前,js引擎会先将,function声明和var变量声明提前,将他们预解析到js的执行栈中
console.log(a)
var a=100
//结果为undefind,而不是报错
var a
console.log(a)
a=100
//预解析过程
var和let,const的区别(重点)
var声明的变量,会挂载到全局对象上,作为全局对象的一个属性保存
- var声明的变量,在定义前可以访问,返回undefind
- var声明的变量,不存在块级作用域
- 对未定义的变量直接赋值,默认由var 声明成全局变量
let,const声明变量存在块级作用域
- let,const声明变量在预解析阶段,存在暂时性死区!不允许在定义前使用
- let ,const不允许在同一作用域下声明同名变量或函数
const 常量必须有初始化赋值,不能只声明
字符串操作(重点)
由单引号,双引号或者``包裹的字符
``模板字符串可以插入变量${变量},可识别/n换行符
str.length
查看字符长度
let str= 'hellow world'
console.log(str.length)
str.charAt()
获取索引字符
str.charAt(1)//结果为e
str.split()
分割字符串,返回字符串数组
let strArr= str.split(' ')//用空格分割
//strArr输出是[hellow,world]
替换字符
str='helow--world--!!'
strArr= str.split('--')//['helow','world','!!!']
let b=strArr.join(' ')//用空格拼接数组
//b的输出结果为 'helow world !!!'
str.trim()
去除首尾空格,不需要传入参数
str.trim()//去掉字符串首尾空格
str.trimStart()//去掉字符串开始的空格
str.trimEnd()//去掉末尾的空格
str.substring()
截取字符串:str.substring(截取字符起始索引,结束索引)
口诀:前截后不截,左闭右开
let str='hellow'
let b=str.substring(0,3)
//b的输出结果为'hel',前截后不截
//第二个参数可以省略
str.indexOf()
查询字符在字符串中的位置,返回下标
str.indexOf('word')
str.lastIndexOf('word')
//没找到返回-1
Str.includes()
查询字符串是否存在某个子串
let a="你好哈哈哈,拜金主义"
a.includes("拜金")
//有就返回true,没有返回false
str.startsWith()
判断字符串是否以指定字符开头,返回布尔值
str.startsWith('h')//是h则返回true
str.endsWith('h')//是否用h结尾
str.toUpperCase()
将字符串中的英文转化成大写,不用传参
str.toLowerCase()
将字符串中的英文转换成小写
str.repeat()
重复字符串,参数传入重复次数
str='abc'
str.repeat(2)//重复两次
//输出结果为abcabc
str.replace()
替换字符,第一个参数是要替换的字符,第二个参数是新字符
let str='abc'
let b = str.replace('b','新')
//结果为'a新c'
//替换所有匹配的字符
let a = "黄s赌h毒黄黄黄哈哈哈"
let b = a.replace(/[黄赌毒]/g, '口')
console.log(b);
//结果为口s口h口口口口哈哈哈
基本数据类型
值数据类型:
string,Number ,BigInt, Boolean,
undefind,Null不算值类型
引用数据类型:
object,Symbol(符号类型)
假值
0," 空字符串",false,NaN,undefind,null
内存堆栈与垃圾回收(理解)
在栈调用函数时,会创建数据并进入栈
函数调用结束后将函数中的数据从栈中移除,出栈
出栈时,释放内存中已经没用的数据,这个过程叫垃圾回收
栈的存放顺序是先进后出。
正则表达式
创建方式
- 直接创建 let regex=/^$/,双斜杠
- 构造函数 regex= new RegExp('^$')
^匹配开头
匹配某段字符开头
let regex=/^123/
console.log(regex.test('123'))
//结果为true
例如:/^123/,匹配是否以123开头,返回true/false
$匹配结尾
匹配字符串结尾
let regex=/123a$/
console.log(regex.test('b123a'))
//结果为true
*匹配任意次数(前一个字符)
regex=/go*ds/
//o可以出现任意次数,没有也可以
//regex.test('ds')结果为false
?匹配0次或1次(前一个字符)
regex=/go?ds/
//o出现一次或者0次,多了不行
+匹配至少一次(前一个字符)
regex = /go+d/
//o至少出现一次,不能没有
{n}匹配指定次数
regex = /go{2}ds/
//o要出现两次,多了不行,少了也不行
{n,}匹配至少指定次数
regex = /go{2,}d/
{n,m}匹配至少n,至多m
regex =/go{2,3}ds/
//o之少要出现2次,最多3次
console.log(regex.test('gooods'))
//结果为true
[xyz]匹配字符集
regex = /st[abc]rt/
//start符合
//stbrt 符合
//stert, 不符合
[^xyz]不能匹配xyz字符
就是xyz不能取
regex = /ab[^cd]rs/
//abcrs,不符合,第三字符有c
//abdrs,不符合,第三字符有d
[x|y]匹配其中一个
或,匹配其中一个,不能没有
regex = /^你[好|不好]/
//你好,符合
//你不好,符合
//你不行,不符合
[a-z]匹配取值范围
匹配取值范围中的一个,还可以是[0-9],[a-d]什么的
regex =/a[b-d]b/
//acb,符合
//abb,符合
//aeb,不符合
[^x-y]不能匹配的范围
regex = /a[^0-9]c/
//a2c,不符合
//abc,符合
( )分组符,括号内视作一个字符
regex = /a(bc)+d/
//这表示bc至少吹按一次
断言
先行断言
x(?=y),x后面一定跟y
先行否定
x(?!y),x后面一定不跟y
后行断言
(?<=y)x,x的前面一定是y
后行否定
(?<!y)x,x前面一定不是y
math()
从字符中匹配一个符合正则的字符串
返回值是包含匹配结果的数组。只会匹配第一个符合条件的
let str='123456'
let regex = /2/
let res=str.match(regex)
mathAll()
查找所有匹配的子串,返回值是一个可迭代的对象,使用需要用Array.from()转义
或者用for of语句遍历可迭代的对象
注意:
使用mathAll的时候正则必须要开全局
let regex = /hh$/g
//这个g就是开启全局
特殊字符
\s,不可见字符
\S,所有可见字符
\w,字母数字下划线
==·==,除换行符以外的任意字符
\r,回车
\n,换行
\d,十进制
\D ,非十进制
闭包和定时器(重点)
定时器
- 一次性定时器 setTimeout()
- 重复性定时器 setInterval()
setTimeout( ()=>{},timeout)
setInterval(()=>{},interval)
timeout和interval都是毫秒,1000ms==1s
定时器==内的回调函数==是属于异步操作,他的执行不会影响主线程的代码
定时器中的回调函数必须满足两个条件
1.定时器时间到了
2.主线程是空闲状态
关闭定时器
两个定时器创建都会返回一个定时器id号,它是唯一的
let ti1= setTimeoout(()=>(),2000)
//ti1就是这个定时器的id
function clearTime(){
//关闭定时器
clearTimeout(定时器id);
clearInterval(定时器id);
}
闭包
定义:闭包是一个封闭的空间,里面存放着一些数据,只能由闭包的持有者才能访问(持有者可以有多个)
闭包本质:函数外部无法访问函数内部的变量!通过闭包,就可以让函数外部访问函数内部的数据。
假设有两个函数,一个函数A,一个函数B
B函数是嵌套在A函数内部!
并且B函数中,在执行时需要用到A函数中的变量或者其他的函数等数据!
最终,当A函数在执行时,执行完毕后,通过某种手段,它又将 B函数给 ‘交’ 出去!A函数的外部可以访问到B函数,调用B函数!
这个时候,如果B函数被‘交’出去,那么它会携带它所需要的一些数据!打包!跟随B函数一起'交'出去,这个过程就称为创建了闭包!
注意:
1.==必须是函数嵌套才能闭包==
2.==被嵌套的函数要使用外部函数的数据==,
3.==这个被嵌套的函数要交出去==
function a(){
let num=100
function b(){
num++
}
return b //交出去的时候,它会把它可能需要用的数据打包{num:100}
//或者 let c2=b
}
let c=a()
//这时候就产生了闭包
==缺点==:闭包会带来内存泄漏(内存被占用了,但是你看不见)
解决:c=Null,让变量指向空,即可释放内存
节流和防抖(重点)
防抖
当函数在一个固定时间后被调用,若计时未完成又执行该函数,则取消上次计时,重新开始计时
用于限制频繁的网络请求,例如:搜索功能,用户停止一段时间后才会执行搜索
特点:先计时,后执行
//防抖函数的封装
const fangdou = (callback, time) => {
let timer
return () => {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
callback()
}, time)
}
}
节流
当函数被触发后,在固定时间内不能再次触发,也就是说在固定时间内,函数只能执行一次
这叫节流
//封装节流
const jieliu = (callback, time) => {
let timer
return () => {
if (timer) { return }
callback()
timer = setTimeout(() => {
clearTimeout(timer)
timer = null
}, time)
}
}
数学函数Math
三角函数(sin())返回的是弧度
Math.abs()绝对值
Math.floor()一个小数向下取整
-1.1//结果为-2
Math.ceil()一个小数向上取整
Math.ceil(1.5)//结果为2
Math. round()四舍五入
Math. round(4.5)//结果为5
Math. max()最大值
Math.max(1,2,3)//结果为3
Math. min()最小值
Math.min(1,2,3)//结果为1
Math.random() 取随机数,范围在[0~1)之间,能取到0但取不到1
Math.random()*5//取0~5之间的数
Math.pow(x,y)返回x的y次方
math.sqrt(n) 返回一个数的平方根
math.sign:(n)取数前的符号(+或-)
console.log(Math.sign(25)) // 1
console.log(Math.sign(-25)) // -1
console.log(Math.sign(0)) // 0
console.log(Math.sign(-0)) // -0
num.toFixed()保留小数点
保留小数点后面几位,四舍五入
let num=3.12345
num.toFixed(2)//结果是3.12
时间对象
格林威治时间:1970-1-1,经过时间单位是毫秒
日期对象
let date = new Date()
//获取当前时间
时分秒创建
date = new Date(2021,0,19,9,40,55)
//月份是从0开始计算的
//分别代表 年,月,日,时,分。秒
读取时间
date.getTime()//获取当前时间到格林威治时间的毫秒数
date.getFullYear()//获取年份
date.getMonth()//获取月份,注意从0开始,真月份要加1
date.getDay()//获取星期数,0表示星期天,取值0~6
date.getDate()//获取天数
date.getHours()//小时
date.getMinutes()//分钟
date.getSeconds()//秒
date.getMillseconds()//毫秒
字符串补位(补零)
time = time.toString(t).padStart(2,"0")
解释:该Api是字符串的api,所以需要将数据转换成字符串,在调用api
padStart第一个参数是位数,表示需要将字符补成多少位的字符,此处表示补成两位
第二个参数表示用什么去补,此处用”0“去补,如果位数本身就达到要求,则该方法不会执行
获取时间戳
(当前至格林威治时间 的时间段的毫秒数)
Date.now()
date.getTime()
这个date要先定义例如:let date = new Date( )
设置时间
date.setFullYear(2021) // 设置年
date.setMonth(1) // 设置月
date.setDate(19) // 设置日
date.setHours(10) // 设置小时
date.setMinutes(28) // 设置分钟
date.setSeconds(30) // 设置秒
date.setMilliseconds(999) // 设置毫秒值
事件的基础
事件是指某个事情的发生
三要素:事件源,事件处理函数,事件类型
事件处理函数不是开发人员调用的,它是由js内部引擎来执行的
事件的绑定
对某个对象的某个事件绑定相关的事件处理
当某个事发生时,从而关联产生的现象或者方法,这叫事件发绑定
绑定事件方式
1.利用html标签中的事件属性 onXX进行绑定
<button onClick='fun1'></button>
function fun1(){}
2.利用dom元素对象,onXX事件属性进行绑定
let btn =document.querSelector('.btn')
btn.onClick = function(){}
3.利用事件监听进行绑定
let btn =document.querSelector('.btn')
btn.addEventListener('click',()=>{})
区别:onClick对应的元素只能对应一个事件处理函数,处理相同的事件,不同的事件函数会被覆盖
addEventListener绑定的事件是一个元素可以绑定多个事件,并且对应的事件处理函数可以是不同的
事件解绑
let btn = document.querSelector('.btn')
btn.onClick = null
let btn = document.querSelector('.btn')
btn.addEventListener('click',function fun1 (){})
btn.removeEventListener('click',fun1)//解绑对应的事件处理函数
==一次性事件==
btn.addEventListener('click',function(){
//事件处理
//解绑事件
btn.removeEventListener('click',arguments.callee)
})
//arguments.callee就是指向当前函数本身
因为只触发一次事件,所以要在事件函数执行完成后解绑
常用事件
window.addEventlistener('load',()=>{})
window.addEventlistener('error',()=>{})
//资源加载完成,资源加载失败
鼠标事件
focus获取焦点 ,常用于表单
blue失去焦点,常用于表单
click 左键点击事件
contextmenu 鼠标右键点击事件
dblclick 双击事件
mousedown 鼠标按下事件
mouseup 鼠标抬起
mouseenter\ mouseover鼠标移入
mouseleave\mouseout 鼠标移出
mousemove 鼠标移动
wheel 鼠标滚轮
change 当值发生变化时触发,多用于表单元素
按键事件
keydown 按钮按下
keyup 按钮弹起
keypress 按钮按住不放事件
注意:
1.div通常情况无法获得焦点,也就无法绑定keydown和focus
所以需要给div添加一个属性tabindex
<div tabindex='0'></div>
<input tabindex='1'>
//这样div就能获取焦点了,数值越大越先获取焦点
2.mouseover和mouseout会触发事件冒泡机制,当其中有子元素的时候
鼠标在移入子元素的时候也会触发事件。
mouseenter和mouseleave则不会触发事件冒泡
事件的冒泡机制
事件的触发的一种过程,==所有事件默认都会在冒泡阶段触发==
由内向外,由下向上触发
事件的捕获
由外到内触发函数,从上向下触发
在**addEventListener('click',()=>{},true)**第三个参数可控制事件是在捕获过程中触发,还是在冒泡过程中触发,==设置成true就在捕获过程中触发,默认为false==
事件对象event
事件函数在执行时,浏览器会自动传入一个对象到该函数
这个对象叫事件对象,它存储了很多事件触发的信息
event.target:指向事件触发的源头
event.currentTarget :永远指向绑定该事件的元素
两者都是触发当前事件的dom元素节点,例如div的点击事件触发,那么这两个都是这个div元素
节点事件的代理
==给想触发点击事件元素的父元素进行绑定事件==,点击子元素,通过事件的冒泡,我们还是能触发点击事件的,这时候事件对象event.target就能帮我们拿到被点击的子元素节点,从而进行事件的处理
阻止事件冒泡
event.stopPropagation()
想在哪里阻止就在哪里面写这句
阻止默认事件
event.preventDefault()
有些元素自带事件,例如表单的提交按钮,可以用这句话阻止
JS委派事件
通过一个事件来触发另一个元素的事件
let ev= new Event('click',{
bubbles:true,//是否允许该事件冒泡
cancelable:false,//是否允许该事件被取消
})
btn.dispatchEvent(ev)
//创建一个事件对象,该事件是一个点击事件
//通过dispatchEvent来发送这个事件,谁触发这个事件,谁就是目标
//此处的btn按钮就是目标
自定义事件
自定义事件长用于数据传递,数据交互
1.先绑定一个自定义事件
btn.addEventListener('my-click', (ev) => {
console.log('哈哈')
console.log(ev.detail.name, ev.detail.age)
})
2通过其他事件来触发
btn2.addEventListener('click', (ev) => {
// 需求:点击btn2去触发btn1的my-click自定义事件,利用js代码形式
// 触发的同时携带一些数据到btn中
// 1.创建一个自定义事件对象
// 注意:自定义事件对象的使用和事件对象的使用方式基本一致
let customEvent = new CustomEvent('my-click', {
bubbles: false, //是否允许该事件冒泡
cancelable: true, //是否允许该事件被取消
detail: {
name: '张三',
age: 18,
},
})
// 2.委派事件, 发送事件
btn.dispatchEvent(customEvent)
})
自定义事件用的是构造(new)==CustomEvent对象==
在这个CustomEvent对象中含有detail属性用来存放要传递的数据
JS中的异步操作(重点)
js运行环境是单线程的,一次执行一个任务,所以多任务需要排队,
异步可以理解为改变执行顺序的操作,异步任务必须在同步任务执行结束之后,从任务队列中依次取出执行。
1.回调函数
function A(){
console.log('A');
callback();//函数A执行了函数B
}
function B(){
console.log('B')
}
A(B);//函数B作为函数A的入参
//B()就是A()的回调函数
缺点:结构紊乱,回调函数不能使用try catch捕获错误,不能直接return
2.Promise
回调层级变多,回调结构会变得非常紊乱形成了回调地狱,
Promise就是解决了回调层级过多,回调地狱的问题
==Promise本身是同步,then的内容才是异步的==
promise包含三种状态:pending,resolved,rejected
let p = new Promise((resolve,reject)=>{
console.log('promise本身是同步')
resolve('then是异步')
}).then((res)=>{
console.log(res);
})
pending是promise的初始状态,resolved表示执行完成且成功的状态,rejected表示执行完成且失败的状态。三个状态不可逆转。
3.Generator函数
Generator 是一个可以暂停执行(分段执行)的函数,函数名前面要加星号,是一个状态机,封装了多个内部状态。
function *myGenerator() {
yield 'hello';
yield 'world';
yield 'wawawa';
return 'amazing';
}
let mg = myGenerator();
mg.next();
//分段执行,直到遇到return结束
4.async/awiat
async函数的返回值是 Promise 对象
await命令后面,可以是 Promise 对象和原始类型的值
async sum(){
let res = await 1
}
sum();
捕获异常
JS中出现异常一般程序都会停止执行
JS中的异常可以人工捕获,解决处理它并防止程序中断
特点:try..catch,它们是一对,不能单独存在
try{
//执行语句
}catch (err){
//当try中的语句发生异常时候,才会执行catch中的语句
err.message=='除数不能为0'
//message是错误对象的一个提示属性
}
finally{
//finally里的代码一定会执行,不管有没有错
}
//构建一个错误对象
let error new Error('除数不能为0')
throw error
//错误对象一定要抛出
注意:throw error抛出错误对象后就会被catch拿到
面向对象
面向对象是一种编程思想,将所有抽象的物体描述成一个类,由类创建对应的实例对象
对应类,是具备对应的属性和行为两个特征
面向对象:它是创建一个实例对象,操作该对象,完成对应的问题
面向过程
面向过程也是一种编程思想
将编程中所遇到的问题,一步一步的拆解并解决,解构的过程
例如:怎么把大象关进冰箱,1打开冰箱门,2把大象放进去,3关上冰箱门
提示:面向对象(狗吃屎),面向过程(吃狗食)
什么是对象
是对现实事物的一种具体描述
描述对象的一些属性和行为所产生的一种数据结构
//读取属性方式
stu.name
stu['name']
stu['eat']()
序列化:将json对象转换成字符串
JSON.stringify()
JSON.parse():转回来
this(重点)
this关键字主要是代指当前的执行上下文中的对象
在非严格模式下
1.this在全局执行上下文中指向window
2.this在函数执行上下文中指向window
function stu (){console.log(this)}
//this指向window,该方法是直接写在全局中的
3.this在对象方法中执行上下文,指向这个对象,==this指向的是它的调用者 而非持有==
let obj={ eat:function(){console.log(this)} }
let obj2={eat:obj1.eat}
obj2.eat
//this指向obj,在对象的方法中this指向该对象本身
//this指向的是它的调用者 而非持有者
4.this在构造函数和类中指向都是实例化的对象(new创建的)
function Person() {
console.log(this)
}
Person() // this指向 window
new Person() // this指向 Person {}
------------------------------
//类中
class stu{
constructor(name) {
console.log(this)//结果为 stu{}
this.name = name
}
eat() {
console.log(this)
}
}
let s1 = new Student('张三')
s1.eat()//结果为stu {name: '张三'}
//this指向s1
在严格模式下,this在函数内指向undefined
5.箭头函数中的this
==箭头函数没有自己的this==
它的this永远指向的是,==该函数被创建时,当前执行上下文中的this==
let obj3={
fun:()=>{ console.log(this) },
func: function(){
let f2 = ()=>{ console.log(this) }
f2() //这个时候箭头函数才创建出来,它的this就是function的this
}
}
obj3.fun() //this 指向window
obj3.func() //this 指向obj3
let obj1 = {
name: 'obj1',
fun: () => {
console.log(this, '@')
},
}
obj1.fun() // 结果是window
let test1 = obj1.fun
test1() // 结果是window
let obj3 = {
name: 'obj3',
fun: obj1.fun,
}
obj3.fun() // 结果是window
6.this的劫持
==箭头函数不能被劫持==
call,apply,bind
let obj2={ name:'obj2',
fun:function(){console.log(this)}
}
----------------------------------
//call方法
// 参数一:新的this的指向
// 参数二:接受一个实参列表的参数
function myfun(a,b){
console.log(this)
} //this指向window
myfun.call(obj2,100,200)//这时myfun的this指向了obj2
-----------------------------------
// apply 方法 和call方法基本一致
// 参数一:新的this的指向
// 参数二:接受一个实参列表的数组
myfun.apply(obj2, [100, 200])
----------------------------------
// bind 方法执行后会返回一个新的函数,该函数是对需要被劫持函数的一个深拷贝
myfun.bind(obj2, 100, 200)()
super关键字
super‘关键字只能用子类,在子类的constructor构造器中使用。
super就相当于父类的构造器,子类在构造自己属性的时候必须要
用一次super(),才能使用this关键字
class person{
constructor(name,age,sex){
this.name =name
this.age =age
this.sex =sex
}
eat(){console.log("吃了")}
}
//子类继承父类
class student extends person{
constructor(name,age,sex,num){
super(name,age,sex),
this.num=num
}
study(){
console.log("在学")
}
eat(){console.log("这是子类的eat方法")}
//在子类中可以调用父类的方法
test(){
super.eat(),//结果为"吃了"
}
}
//super可以调用父类的方法,但是super无法访问父类的属性
//super关键字不允许单独打印查看
//super只能写在函数方法里面
类
类的创建
class xx{ }
类的静态属性和方法
由类自身调用的属性和方法称为静态类,==用static修饰==
//定义类
class peson{
name ='张三'
static xx ='只能类本身调用'
constructor(){}
}
let p = new peson()
p.name//结果为张三
p.xx//结果为undefind
peson.xx//结果为,只能类本身调用
类的私有属性和方法
只能在类的内部使用的属性和方法,==用#修饰==
目的:让外部无法访问操作对应的数据,保证数据的安全性
//定义类
class peson{
name ='张三'
#xx ='只能类本身调用'
test(){
console.log('this.#xx')
}
constructor(){}
}
let p = new peson()
p.name//结果为张三
p.#xx //直接报错
peson.xx//结果为,只能类本身调用
只能在类的内部使用
类的继承
class Person{ constructor(){}}
class Student extends Person{
constructor(){
super()//必须用super来执行一次,这样子类才能构造属性
this.name =name
}
}
判断对象是否包含某个key
let obj={a:1,b:2,c:''}
方法一:短路与(如果一开始就是false,则后面不执行)
obj.a && console.log('a存在')
如果a不存在,则后面的打印不会执行
==缺点==:如果c是空值或者0或者false后面的打印也不会执行,但是c存在
方法二:key in obj
“a” in obj && console.log('a存在')
返回值是布尔值,存在true,不存在false
方法三:使用 Reflect 反射
Reflect.has(obj, 'c') && console.log('obj对象存在 c')
Object类上的静态方法
Object.assign(),扩展对象,
返回值:扩展对象的索引(地址)
let A ={num:1}
let B ={a:2,b:3,c:4}
Object.assign(A,B)
console.log(A)
//结果为{num:1,a:2,b:3,c:4}
let res =Object.assign(A,B)
console.log(res === A)
//结果为true
Object.assign({},B)//可以深拷贝对象
Object.defineProperty(),创建一个新的属性
let A={name:'张三',age:25}
Object.defineProperty(A,"sex",{
value: 'man',//这个新属性的值
enumerable: false,//这个属性能不能被枚举出来(for in 遍历到)
writable: false //这个属性能不能被更改
//默认为false
})
Object.defineProperty(A,"sex",{})
第三个参数不能被省略,可以写个空对象
---------------------------
// defineProperty
// 参数一:被操作的对象
// 参数二: 操作的该对象的属性
// 参数三:对该属性的配置描述 配置对象
Object.toString(),强转字符串
类和对象中的访问器 get,set
作用:可以控制读取属性的结果,可以控制赋值属性的内容
let obj={
name:"张三",
_sex:"man",
//读值
get sex(){
return this._sex
},
//控制赋值
set sex(value){
if(value==man||value==woman){
this._sex=value
return
}
console.log("数据不正确")
},
}
obj.sex="woman"
obj.sex
//注意虽然sex是方法,但是是用get,set修饰的,所以不用()
//set sex(value),value传参不能省略
//数据名称不能和方法名称同名,一定要有所区分(_sex,sex())
JS中的继承和原型
js中的继承是如何实现的
答:利用了原型对象实现的继承,在js中所有的构造函数对象上都具备
两个原型属性,
在js中所有的构造函数对象身上都有两个属性
prototype属性:显示原型
--proto--(下划线)属性:隐藏原型
prototype属性只存在可以构造实例对象的数据上
--proto--属性==存放着该实例对象的原型对象==
例如:
stu.__proto__ === clazz.prototype
function Person(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
}
let p1 = new Person('张三1', 18, 'male')
let p2 = new Person('张三2', 18, 'male')
console.log(p1.__proto__ === Person.prototype)//true
console.log(p2.__proto__ === Person.prototype)//true
//p1,p2没有构造器constructor,所以它只有__proto__属性指向原型
//没有prototype属性
new做了以下几件事情:
1.创建了一个该类型的实列的空对象
2.它将刚创建出来的实列对象的--proto-- 属性 重新指向为 构造函数中 prototype所指向的那个对象
3.将构造函数中的this指向为该实例对象
4.返回该实例对象