手写 Promise 实现
最小可用版 Promise:状态机、then/catch、all/race/any/resolve
<script>
class MyPromise{
constructor(initFn){
this.state = 'pending';
this.value = null;
this.errReason = null;
this.onSuccessCallbacks = [];
this.onErrorCallbacks = [];
const resolve = (value) => {
if(this.state === 'pending'){
this.state = 'fulfilled';
this.value = value;
this.onSuccessCallbacks.forEach(callback => callback());
}
}
const reject = (reason) => {
if(this.state === 'pending'){
this.state = 'rejected';
this.errReason = reason;
this.onErrorCallbacks.forEach(callback => callback());
}
}
try{
initFn(resolve, reject);
}catch(error){
reject(error);
}
}
then(onSuccess, onError){
if(this.state === 'fulfilled'){
onSuccess && onSuccess(this.value);
}
if(this.state === 'rejected'){
onError && onError(this.errReason); // ← 检查是否存在
}
if(this.state==='pending'){
if(onSuccess){
this.onSuccessCallbacks.push(() => {
onSuccess(this.value);
});
}
if(onError){ // ← 检查是否存在
this.onErrorCallbacks.push(() => {
onError(this.errReason);
});
}
}
return this
}
catch(onError){
// catch 应该检查状态
if(this.state === 'rejected'){
onError && onError(this.errReason);
}
if(this.state === 'pending'){
if(onError){
this.onErrorCallbacks.push(() => {
onError(this.errReason);
});
}
}
return this
}
static all(promises){
return new MyPromise((resolve,reject)=>{
const results = [];
let completedCount = 0;
if(promises.length===0){
resolve(results);
return;
}
promises.forEach((promise,index)=>{
MyPromise.resolve(promise).then(res=>{
results.push({
index,
promise:promise,
res:res
})
completedCount++;
if(completedCount===promises.length){
resolve(results);
}
},(err)=>{
reject(err);
})
})
})
}
static race(promises){
return new MyPromise((resolve,reject)=>{
promises.forEach(promise=>{
//只要有一个成功,就返回
// 执行单个promise的then方法,但是会把外层的resolve和reject传给单个promise的then方法,作用是调用时返回的参数是单个promise对应的resolve赋值时里面的value值
MyPromise.resolve(promise).then(resolve,reject)
})
})
}
static any(promises){
return new MyPromise((resolve,reject)=>{
if(promises.length===0){
reject('All promises were rejected');
return;
}
let rejectedCount = 0;
promises.forEach((promise,index)=>{
MyPromise.resolve(promise).then((res)=>{
resolve(res);
},(err)=>{
rejectedCount++;
if(rejectedCount===promises.length){
reject('All promises were rejected');
}
})
})
})
}
static resolve(value){
//判断是否为MyPromise的实例
if(value instanceof MyPromise){
return value;
}
//如果不是,则包装成MyPromise的实例
return new MyPromise((resolve)=>{
resolve(value);
})
}
}
const p1 = new MyPromise((resolve, reject) => {
resolve('success');
});
const p2 = new MyPromise((resolve, reject) => {
reject('error');
});
const p3 = new MyPromise((resolve, reject) => {
resolve('success');
});
p1.then(res => {
console.log(res);
}).catch(err => {
console.log(err);
});
MyPromise.all([p1,p2,p3]).then(res=>{
}).catch(err=>{
console.log(err);
});
</script>SHA-256 哈希生成
浏览器环境下使用 Web Crypto API 生成 SHA-256 哈希值
<script>
async function sha256Browser(text) {
// 编码为 Uint8Array
const encoder = new TextEncoder();
const data = encoder.encode(text);
// 计算哈希
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
// 转换为十六进制
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
return hashHex;
}
// 使用示例
sha256Browser('hello').then(hash => {
console.log('SHA-256:', hash);
// document.getElementById('result').textContent = hash;
});
</script>事件冒泡、捕获与委托
演示事件流的三个阶段:捕获、目标、冒泡以及 stopPropagation 的作用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="outer">
<button id="btn">点击我</button>
</div>
</body>
<script>
// 场景1:按钮阻止了冒泡
document.getElementById('btn').addEventListener('click', (event) => {
console.log('按钮被点击');
event.stopPropagation(); // 阻止冒泡!
});
// 不加 capture: true - 收不到事件
document.getElementById('outer').addEventListener('click', () => {
console.log('外层容器(冒泡)- 这里不会执行!');
});
// 加 capture: true - 仍然能收到事件
document.getElementById('outer').addEventListener('click', (event) => {
console.log('外层容器(捕获)- 这里正常执行!');
}, { capture: true });
// 输出:
// 外层容器(捕获)- 这里正常执行!
// 按钮被点击
// 外层容器(冒泡)- 不会执行(被stopPropagation阻止)
</script>
</html>手写 Ajax 封装
原生 XMLHttpRequest 封装,支持请求头、成功/失败回调
export function ajax(data) {
let xhr = new XMLHttpRequest();
// 初始化请求
xhr.open(data.method || "GET", data.url, true);
// 设置请求头
if (data.headers) {
for (let key in data.headers) {
xhr.setRequestHeader(key, data.headers[key]);
}
}
// 发送请求
xhr.send(data.data || null);
// 处理响应
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
//请求完成
if (xhr.status === 200) {
//请求成功
data.success && data.success(xhr.response);
} else {
//请求失败
data.error && data.error(xhr.status);
}
}
};
}Web Components 自定义元素
使用原生 JS 创建可复用的自定义 HTML 元素,支持 Shadow DOM 样式隔离
// 创建自定义元素类webComponents.js
class MyButton extends HTMLElement {
constructor() {
super();
// 创建Shadow DOM(样式隔离)
const shadow = this.attachShadow({ mode: "open" });
// 定义组件的HTML和CSS
shadow.innerHTML = `
<style>
button {
padding: 10px 20px;
background: blue;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background: darkblue;
}
</style>
<button><slot></slot></button>
`;
}
}
customElements.define("my-button", MyButton);
//其他页面引入
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Web Components 示例</title>
</head>
<body>
<h1>Web Components 演示</h1>
<!-- 像普通HTML标签一样使用 -->
<my-button>
<div>惦记我</div>
</my-button>
<my-button>另一个按钮</my-button>
<!-- 引入外部 JS 文件 -->
<script src="./webComponents.js"></script>
</body>
</html>WeakMap 弱引用示例
演示 WeakMap 如何避免内存泄漏,对比 Map 的强引用特性
<script>
const map = new Map()
function createUser(){
const user = {
name: '张三',
age: 18
}
map.set(user, '李四')
return user
}
let user = createUser()
console.log(map.get(user))
user = null
console.log(map.get(user))
// 1. 创建一个 WeakMap(弱映射-弱映射)
const weakMap = new WeakMap();
// 2. 创建一个对象作为键
function createObj(){
const obj = {
name: '张三',
age: 18
}
weakMap.set(obj, '李四')
return obj
}
// 实现原理
// 1.user变量强引入了user对象
// 2.weakmap以键的形式弱引入user对象
// 3.weakmap以值的形式强引入额外数据
// 4.user= null,不再指向对象,强引用断开,剩下唯一的weakmap弱引用
// 5.垃圾回收器回收weakmap弱引入的user对象。
// 6.weakmap映射删除,额外数据失去引用,同时被垃圾回收
</script>this 指向详解
严格模式、隐式绑定、显式绑定(call/apply/bind)、new 绑定与箭头函数
<script>
// this指向问题
// 严格模式下,this指向undefined
// 1.es6函数内套function,function里面会出现严格模式,自带严格模式
// 2.es6函数内套箭头函数,箭头函数里面不会出现严格模式,不自带
// 隐式绑定 直接调用函数
const user = {
name: '张三',
age: 18,
sayHello: function(){
console.log(this)
}
}
user.sayHello()
// 隐式绑定丢失
// 赋值函数,后续调用会丢失this,从而this指向window
// 显示绑定 call、apply、bind
function createUser(){
console.log(this.name)
}
createUser.call(user)
createUser.apply(user)
let user1 = createUser.bind(user)
user1()
// new 绑定(构造函数) this指向构造函数
function Animal(){
this.name = '动物'
console.log(this)
}
let dog = new Animal()
// 箭头函数没有this指向
let fn1 = () => {}
</script>