【前端知识点整理】JS + AJAX
JS AJAXES6新特性变量声明let 和 constlet、const、var 的区别var存在变量提升没有块级作用域letconst声明的变量不存在变量提升具有块级作用域const声明的是常量不可以改变而let和var声明的是变量可以改变。const声明常量不可改变简单数据类型复杂数据类型只地址不可以改变箭头函数传统函数this 指向函数的调用者谁调用指向谁箭头函数this 固定为定义时的上下文不能作为构造函数js改变 this 指向方法call()、apply()、bind()、箭头函数箭头函数的 this 不能被改变call 和 apply 立即执行bind 返回新函数不执行call 参数逐个传递apply 参数是数组bind 可以预设参数模板字符串解构赋值扩展运算符…新增数据结构Set集合值不重复Map键值对键可以是任意类型类class模块化Promise 和异步编程// 创建 Promise const promise new Promise((resolve, reject) { // 异步操作 setTimeout(() { const success true; if (success) { resolve(操作成功); } else { reject(操作失败); } }, 1000); }); // 使用 Promise promise .then(result { console.log(result); // 操作成功 }) .catch(error { console.error(error); // 操作失败 }) .finally(() { console.log(无论成功失败都会执行); }); // Promise 静态方法 Promise.all([p1, p2, p3]) // 全部成功才成功 Promise.race([p1, p2, p3]) // 谁先完成用谁 Promise.allSettled([p1, p2]) // 等待所有完成不论成功失败 Promise.resolve(直接成功) Promise.reject(直接失败)async await异步函数的同步写法await 只能在 async 函数中使用能用 Promise.all 就别串行循环中用 for…of 而不是 forEach用 try/catch 处理错误迭代器和 for…offor…of 遍历值、for…in 遍历键默认参数常用的数组方法会改变原数组push、pop、shift、unshift、splice、sort、reverse、fill不会改变原数组concat、slice、map、filter、reduce、forEach、some、every、find、findIndex、includes、indexOf、join、flat、flatMap常用的字符串方法都不会改变字符串自身trim() 去除前后空格split() 把字符串按某个字符切分成数组replace() 替换toUpperCase 把字符串中的小写英文字母转成大写toLowerCase 把字符串中的大写英文字母转成小写slice() 提取某个字符串的一部分数据类型简单类型原始类型:string、number、boolean、null、undefined、symbol、bigint赋值的时候传递的是值进行值的拷贝复杂类型引用类型:包括数组、函数、对象、集合等赋值的时候传递的是地址浅拷贝和深拷贝浅拷贝只拷贝第一层属性嵌套对象还是引用// 对象 const copy1 Object.assign({}, obj); const copy2 { ...obj }; // 数组 const copy3 arr.slice(); const copy4 arr.concat(); const copy5 [...arr]; const copy6 Array.from(arr);深拷贝递归拷贝所有层级完全独立// 简单场景无函数/循环引用 const copy1 JSON.parse(JSON.stringify(obj)); // 递归 const copy2 deepClone(obj); function deepClone(obj, hash new WeakMap()) { // 处理 null 或非对象类型 if (obj null || typeof obj ! object) return obj; // 处理日期 if (obj instanceof Date) return new Date(obj); // 处理正则 if (obj instanceof RegExp) return new RegExp(obj); // 处理循环引用 if (hash.has(obj)) return hash.get(obj); // 创建新对象/数组 const clone Array.isArray(obj) ? [] : {}; hash.set(obj, clone); // 递归拷贝所有属性 for (let key in obj) { if (obj.hasOwnProperty(key)) { clone[key] deepClone(obj[key], hash); } } // 处理 Symbol 属性 const symbols Object.getOwnPropertySymbols(obj); for (let sym of symbols) { clone[sym] deepClone(obj[sym], hash); } return clone; } // 第三方库或浏览器 API推荐 const copy3 _.cloneDeep(obj); const copy4 structuredClone(obj); // 现代浏览器 API注JSON.parse(JSON.stringify())不能拷贝函数、undefined、Symbol不能处理循环引用Date 会变成字符串RegExp 会变成空对象NaN/Infinity 会变成 null原型和原型链原型每个函数都有prototype属性指向原型对象每个对象都有__proto__属性指向构造函数的prototype原型链对象通过__proto__连接起来的链式结构用于实现属性和方法的继承概念作用关系prototype函数属性指向原型对象函数.prototype__proto__对象属性指向父原型实例.proto 构造函数.prototypeconstructor原型属性指向构造函数构造函数.prototype.constructor 构造函数原型链属性查找机制实例 → 构造函数.prototype → Object.prototype → null原型链是 JS 实现继承的机制每个对象都有一个隐藏的__proto__指向它的“父亲”找不到属性就沿着这个链条一直往上找直到 null。闭包一个函数内部定义了另一个函数内部函数使用了外部函数的变量内部函数被返回到外部使用。延伸了变量的作用范围常见应用数据私有化封装✅ 变量私有化避免全局污染 ❌ 变量常驻内存可能造成内存泄漏 (及时释放引用fn null避免不必要的闭包)function Person(name) { // 私有变量外部无法直接访问 let _name name; return { getName: function() { return _name; }, setName: function(newName) { _name newName; } }; } const p Person(张三); console.log(p.getName()); // 张三 p.setName(李四); console.log(p.getName()); // 李四 console.log(p._name); // undefined无法直接访问函数工厂返回函数的函数function multiply(x) { return function(y) { return x * y; }; } const multiplyBy2 multiply(2); const multiplyBy5 multiply(5); console.log(multiplyBy2(10)); // 20 console.log(multiplyBy5(10)); // 50循环中的经典问题var// ❌ 错误示例 for (var i 1; i 3; i) { setTimeout(function() { console.log(i); // 输出 4, 4, 4 }, 1000); } // ✅ 解决方案1闭包 IIFE立即执行函数创建独立作用域避免污染全局 for (var i 1; i 3; i) { (function(j) { setTimeout(function() { console.log(j); // 输出 1, 2, 3 }, 1000); })(i); } // ✅ 解决方案2let块级作用域 for (let i 1; i 3; i) { setTimeout(function() { console.log(i); // 输出 1, 2, 3 }, 1000); }防抖和节流// 防抖延迟执行连续触发只执行最后一次回城 function debounce(fn, delay) { let timer null; return function(...args) { // 每次触发都清除之前的定时器 if (timer) clearTimeout(timer); // 创建新的定时器 timer setTimeout(() { fn.apply(this, args); }, delay); }; } // 节流固定频率执行大招 function throttle(fn, delay) { let lastTime 0; return function(...args) { const now Date.now(); if (now - lastTime delay) { lastTime now; fn.apply(this, args); } }; } // 使用 const handleInput debounce((text) { console.log(搜索, text); }, 500);柯里化把一个接收多个参数的函数转换成一系列接收单个参数的函数// 普通函数 function add(a, b, c) { return a b c; } // 柯里化后的函数 function curry(fn) { return function curried(...args) { // 如果参数够了直接执行原函数 if (args.length fn.length) { return fn.apply(this, args); } else { // 如果参数不够返回一个新函数继续收集参数 return function(...more) { return curried.apply(this, args.concat(more)); }; } }; } const curriedAdd curry(add); console.log(curriedAdd(1)(2)(3)); // 6 console.log(curriedAdd(1, 2)(3)); // 6 console.log(curriedAdd(1)(2, 3)); // 6HTTPHTTP 协议超文本传输协议是无状态规定浏览器和服务器之间如何通信浏览器和服务器之间的沟通语言规定了请求和响应的格式特点规定了请求报文和响应报文的格式和内容请求请求url地址、请求方式、请求头和请求体响应响应状态码、响应头和响应体是无状态的是构建在TCP协议之上的应用层协议HTTP 常见状态码1xx信息响应2xx成功3xx重定向4xx客户端错误5xx服务器错误状态码含义说明200成功201创建成功204成功但没有返回数据301永久重定向 资源永久迁移到新 URL302临时重定向 资源临时转移到新 URL400错误请求 请求参数有误401未授权 需要身份认证403禁止访问 没有权限访问404未找到 资源不存在405方法不允许 HTTP 方法不支持429请求过多 触发限流500服务器内部错误502网关错误503服务维护中504网关超时请求方式维度GETPOSTPUTPATCHDELETE作用获取创建整体替换部分更新删除参数位置URLBodyBodyBodyURL请求体❌✅✅✅❌响应体✅✅✅✅可选幂等多次执行结果相同✅❌✅❌✅安全不会修改服务器数据✅❌❌❌❌可缓存✅❌❌❌❌长度限制有(2KB)无无无无Axios 底层实现原理Axios 是用 XMLHttpRequest负责在浏览器中发送请求 和 Promise优化调用方式解决回调地狱问题 实现的跨域当一个网页向不同域名、不同端口、不同协议的服务器请求资源时浏览器会阻止这个请求。它会限制DOM 访问、Cookie/Storage 读取和AJAX 请求根本原因同源策略浏览器的安全机制防止恶意网站窃取用户数据解决方案方案原理适用场景优缺点CORS服务器设置响应头现代 Web 应用✅ 标准方案最常用JSONPscript标签不受限GET 请求老旧浏览器❌ 只支持 GET代理服务器同源请求转发开发环境✅ 简单无需后端改动postMessage窗口间消息传递iframe 通信特定场景WebSocket全双工通信实时应用协议本身支持跨域Nginx 反向代理服务器端转发生产环境✅ 稳定可靠Webpack DevServer// webpack.config.js module.exports { devServer: { proxy: { /api: { target: https://api.example.com, changeOrigin: true, pathRewrite: { ^/api: // 移除 /api 前缀 } } } } };Vite// vite.config.js export default { server: { proxy: { /api: { target: https://api.example.com, changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ) } } } };Nginxserver { listen 80; server_name myapp.com; # 前端静态文件 location / { root /var/www/dist; try_files $uri $uri/ /index.html; } # API 代理转发 location /api/ { proxy_pass https://api.example.com/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }