1.事件绑定
允许监听DOM元素上的各种事件(如点击、滚动、键盘输入等)并执行相应的代码
三种绑定方式:
a.HTML内联事件处理程序
不利于维护;可能导致全局变量污染
<button onclick="handleClick()">点击我</button>
<script>
function handleClick() {
console.log('按钮被点击');
}
</script>
b.DOM0级事件处理程序
通过JS直接赋值给元素的事件属性
每个事件只能绑定一个处理程序
<button id="btn">点击我</button>
<script>
const btn = document.getElementById('btn');
btn.onclick = function() {
console.log('按钮被点击');
};
// 可覆盖之前的事件处理程序
btn.onclick = function() {
console.log('新的点击处理');
};
</script>
c.DOM2级事件处理程序
支持多个处理程序、事件捕获/冒泡控制、更灵活的事件管理
<button id="btn">点击我</button>
<script>
const btn = document.getElementById('btn');
// 绑定事件
btn.addEventListener('click', function() {
console.log('按钮被点击');
});
// 可绑定多个处理程序
btn.addEventListener('click', function() {
console.log('另一个处理程序');
});
// 解绑事件(需使用相同的函数引用)
const handler = () => console.log('可移除的处理程序');
btn.addEventListener('click', handler);
btn.removeEventListener('click', handler); // 成功移除
</script>
事件冒泡与捕获
事件在DOM树中传播有两种机制:
a.事件冒泡(默认)
事件从触发元素开始逐级向上传播到父元素
b.事件捕获
事件从文档根节点开始,逐级向下传播到触发元素
阻止事件冒泡:
a.event.stopPropagation()
最常用
element.addEventListener('click', function(event) {
event.stopPropagation(); // 阻止事件继续冒泡
console.log('事件被捕获,但不会向上传播');
});
b.内联事件使用return false
同时阻止冒泡和默认行为
c.window.event.cancelBubble=true
2.promise
解决回调地狱的问题 有三种状态: pending fulfilled(成功) rejected(失败) 状态改变只能从pending到另外两种 且不能再改变 对象的实例化方法: then catch finally then: 指定用于得到成功value的成功回调和失败回调,返回新的promise实例化对象 成功的状态:执行then的第一个回调函数 失败的状态:执行then方法的第二个回调函数 then方法的返回值的promise实例化对象的状态取决于回调函数中的内容 返回非promise实例化对象,得到成功的promise 抛出异常,得到失败的promise 返回promise实例化对象,则该对象的状态和结果值影响result常量的结果值
const p1=new Promise( (resolve,reject)=>{
resolve('ok');
})
const result=p1.then(value=>{
return value; //状态fulfilled 结果value
return new Promise((resolve,reject)=>{
reject('error') //状态rejected 结果error
resolve('ok') //状态fulfilled 结果ok
})
throw'异常信息' //状态rejected 结果异常信息
},reason =>{
console.log(reason);
})
链式调用 then的执行依赖上一步结果 all方法: 针对于多个promise的异步任务的处理 接受一个数组类型的参数,数组里放的是多个promise实例化对象 返回值:promise对象,状态由数组里的所有promise决定 所有promise都成功,结果成功,结果值由每一个promise的结果值组成 只要有一个失败的就失败,结果值是失败的这个promise的结果
3.深拷贝浅拷贝
浅拷贝:
将原对象或数组的值复制到一个新的对象或数组中,
但新的对象或数组的元素或属性依然是原对象或数组的引用
常见的浅拷贝方法:
①Object.create(obj)
创建一个新对象,并将原对象作为新对象的原型
新对象可以访问原对象的所有属性和方法
const obj2=Object.create(obj1);
②Object.assign({},obj)
用于将一个或多个源对象的属性复制到目标对象中
let a={
name:'A',
like:{n:'coding'}
}
let b=Object.assign({},a);
a.name='B';
a.like.n='running';
console.log(b.name); //A
console.log(b.like.n); //running
原始类型不会跟着a修改,引用类型会
③[].concat(arr)
用于将一个或多个数组合并成一个新数组
修改时同上
④[...arr]数组解构
同上
⑤arr.slice()
从数组中提取指定区间的元素创建一个新的数组
接受两个参数:开始索引和结束索引
深拷贝:
将原对象或数组的值复制到一个新的对象或数组中,
新的对象或数组的属性或元素完全独立于原对象或数组,不共享引用地址
常见的深拷贝方法:
JSON.parse(JSON.stringify(obj))
JSON.stringify将js对象或值转换为JSON字符串
JSON.parse将JSON字符串解析为对应的js对象或值
手写深拷贝
function deepCopy(obj){
//不是引用类型就不拷贝
if(!(obj instanceof Object)) return obj
//如果形参obj是数组,就创建数组,如果是对象就创建对象
let objCopy = obj instanceof Array ? [] : {}
for(let key in obj){
if(obj instanceof Object){
objCopy[key] = deepCopy(obj[key])
} else{
if(obj.hasOwnProperty(key)){
objCopy[key] = obj[key]
}
}
}
return objCopy
}
4.promise
解决回调地狱的问题
有三种状态:
pending fulfilled(成功) rejected(失败)
状态改变只能从pending到另外两种 且不能再改变
对象的实例化方法:
then catch finally
then:
指定用于得到成功value的成功回调和失败回调,返回新的promise实例化对象
成功的状态:执行then的第一个回调函数
失败的状态:执行then方法的第二个回调函数
then方法的返回值的promise实例化对象的状态取决于回调函数中的内容
返回非promise实例化对象,得到成功的promise
抛出异常,得到失败的promise
返回promise实例化对象,则该对象的状态和结果值影响result常量的结果值
const p1=new Promise( (resolve,reject)=>{
resolve('ok');
})
const result=p1.then(value=>{
return value; //状态fulfilled 结果value
return new Promise((resolve,reject)=>{
reject('error') //状态rejected 结果error
resolve('ok') //状态fulfilled 结果ok
})
throw'异常信息' //状态rejected 结果异常信息
},reason =>{
console.log(reason);
})
链式调用
then的执行依赖上一步结果
catch方法:
与then方法类似
可以专门指定失败的回调函数
返回一个Promise对象,返回对象的状态与then方法里一样
const result=p1.catch( reason =>{
console.log(reason)
return reason
return new Promise( (resolve,reject) =>{
resolve('ok')
reject('error')
})
})
可以和then方法结合使用
错误穿透
如果有多个需要执行的成功回调,可以不每一次都写失败回调,一次性使用最后的catch
p1.then( value => {
console.log(value);
}).then( value => {
console.log(value);
}).catch( reason => {
console.log(reason);
})
finally方法(ES9新增):
Promise对象无论成功失败都会执行
回调函数不接受参数
const p1=new Promise( (resolve,reject) =>{
resolve('ok');
})
p1.then( value => {
console.log(value);
}).catch( reason => {
console.log(reason);
}).finally( ( )=> {
console.log('最终....');
})
all方法:
针对于多个promise的异步任务的处理
接受一个数组类型的参数,数组里放的是多个promise实例化对象
返回值:promise对象,状态由数组里的所有promise决定
所有promise都成功,结果成功,结果值由每一个promise的结果值组成
只要有一个失败的就失败,结果值是失败的这个promise的结果
allSettled方法:
接收数组为参数,都有结果了就执行,无论成功失败
用来确定一组异步操作是否都结束了
any方法:
接收数组为参数,只要有一个状态为成功就成功
race方法:
传参为数组
状态和结果以最先到达的为准
reject方法:
返回一个状态为rejected的Promise对象
参数只影响Promise结果
resolve方法:
返回一个状态为resolve的Promise对象
将一个普通的值转化为Promise类型的数据
参数为非Promise对象,返回成功的Promise对象
参数为Promise对象,返回对象的状态取决于参数对象
终止Promise链条
基于then的链式调用
返回一个pending状态的Promise实例
return new Promise( ( ) => { })
一个Promise实例对象指定多个成功/失败的回调函数,都会调用,只要状态不是pending
5.async
任何函数都可以被声明成一个async函数
目的是在内部执行异步的功能,并且得到结果数据值
async function main(){
return 100; //返回非Promise对象的数据 得到成功Promise
return new Promise() //得到的状态取决于这个Promise的状态
throw '出错' //得到失败的Promise
}
let result=main() //调用
result.then(
value =>{}
,reason =>()
)
await表达式
async函数中不一定有await表达式
但有await的函数一定是async函数
await相当于then,可以直接拿到成功的Promise实例化对象的结果值
内部执行异步的功能,并且得到成功的结果数据值
async function main(){
//await右侧是非Promise类型的数据,得到的结果就是await后面的值
let rs=await 100;
console.log(rs); //100
//await右侧是Promise成功类型的数据
let rs=await new Promise ( (resolve,reject) => {
resolve('ok');
reject('error') //接收不到
})
console.log(rs)
//await右侧是Promise失败类型数据,需要try..catch来捕获
try {
let rs=await Promise.reject('error');
console.log(rs);
} catch (e) {
console.log(e);
}
console.log(..); //有try catch后面的代码将继续执行
}
main()
await表达式的执行顺序问题
同步异步代码同时出现,先执行同步,再执行异步
async function main(){
console.log(1);
let result=await Promise.resolve('ok');
console.log(2);
let result1=await Promise.resolve('okk');
console.log(result1)
}
main()
console.log(3)
输出顺序:1 3 ok 2 okk