【2023年1月整理】
| 考点 | 内容 | 备注 |
|---|---|---|
| 数据存储 用户登录 | localStorage、SessionStorage Token、cookie、session、JWT | |
| 深拷贝和浅拷贝 | 浅拷贝:Object.assign方法、ES6 扩展运算符、数组的 slice 和 concat 方法、jQuery 中的 $.extend深拷贝: Object.assign()、JSON 序列化、递归 | 递归、判断类型、检查环(嵌套) |
| 闭包 | 在函数内部再定义一个函数实现读取到函数内的局部变量 | 父对象的所有变量对子对象都是可见的,反之不成立 |
| 节流 throttle | 单位时间内频繁触发事件,只执行一次 典型场景:高频事件快速点击获取验证码 | 代码实现思路:利用定时器,等定时器执行完毕,才开启定时器 |
| 防抖 debounce | 单位时间内,频繁触发事件,只执行最后一次 典型场景:搜索框搜索输入 | 代码实现思路:利用定时器,每次触发先清掉以前的定时器 开发中一般用 lodash库 |
| async / wait ES8新特性 | 解决面条地狱(链式调用太多) | |
| Promise | .all方法:成功时返回结果数组 失败时返回最先被reject失败状态的值.race方法:哪个结果获得快,就返回哪个结果 | |
| Axios | 基于promise封装的网络请求库 是基于XHR进行二次封装 | |
| 同源策略和跨域 | 同源是指两个URL的协议、端口和域名都相同 跨域手段有JSONP和CORS | |
| Webpack和vite | 开发环境:vite不打包代码利用浏览器module支持 w打包 生产环境:vite用rollup+esbuild打包代码 w用babel打包 慢 文件处理时机:vite只在请求文件时 w提前打包 | vite缺点:热更新总失败、部分功能rollup不支持 |
| loader与plugin区别 | l是文件加载器 在创建最终产物之前运行 p是插件在整个打包过程都能运行 | |
| HTTP缓存方案 | 强缓存和协商缓存 | |
| HTTP和HTTPS的区别 HTTPS = HTTP+SSL加密 | HTTP明文传输 +s加密传输 HTTP使用80端口 +s使用443端口 HTTP不需CA证书 +s需要证书 HTTP速度快 +s有复杂的SSL握手 | HTTPS使通信不容易受到拦截和攻击 |
| Vue组件间通信方式 | 父子组件用props和事件爷孙用依赖provide注入inject 任意组件用eventBus或vuex、Pinia |
深拷贝 浅拷贝的方式
什么是深拷贝、浅拷贝
浅拷贝是指,对基本类型的值拷贝,以及对象类型的地址拷贝。
深拷贝是指,除了拷贝基本类型的值,还完全复刻了对象类型。(新旧对象没有关联或交集,完全隔离)
浅拷贝举例:
var a = 1;
var b = a; // 浅拷贝-值拷贝
console.log(b); // 1
b = 2;
console.log(b); // 2
console.log(a); // 1
如何实现 浅拷贝
1. 直接赋值
var p1 = {
name:'jack',
age:12
}
var p2 = p1; // 浅拷贝-对象地址拷贝
console.log(p2); // {name:'jack', age:12}
p2.age = 20;
console.log(p2); // {name:'jack', age:20}
console.log(p1); // {name:'jack', age:20}
2. Object.assign方法
var user1 = {
name : "法医"
}
var user2 = Object.assign(user1, {age : 18}, {sex : 'male'});
console.log(user2); // { name: '法医', age: 18, sex: 'male' }
当属性对应的一个值是引用类型时,此方法是一个浅拷贝。
3. ES6 扩展运算符
var user1 = {
name: "法医",
like: {
eat: "面条",
sport: "篮球",
},
};
var user2 = {...user1};
console.log(user1); //{name: '法医', like: {eat: '面条', sport: '篮球'}}
console.log(user2); //{name: '法医', like: {eat: '面条', sport: '篮球'}}
user1.name = "前端猎手";
console.log(user1); //{name: '前端猎手', like: {eat: '面条', sport: '篮球'}}
console.log(user2); //{name: '法医', like: {eat: '面条', sport: '篮球'}}
user1.like.eat = "米饭";
console.log(user1); //{name: '前端猎手', like: {eat: '米饭', sport: '篮//{name: '法医', like: {eat: '面条', sport: '篮球'}}球'}}
console.log(user2); //{name: '法医', like: {eat: '米饭', sport: '篮球'}}
4. 数组的 slice 和 concat 方法
// 使用 slice 截取 和 concat 拼接 方法来拷贝数组
var user1 = ["法医",{eat:"面条",sport:"篮球"}];
var user2 = user1.slice();
var user3 = user1.concat();
console.log(user1);//{name: '法医', like: {eat: '面条', sport: '篮球'}}
console.log(user2);//{name: '法医', like: {eat: '面条', sport: '篮球'}}
console.log(user3);//{name: '法医', like: {eat: '面条', sport: '篮球'}}
user1[0] = "前端猎手";
console.log(user1);//{name: '前端猎手', like: {eat: '面条', sport: '篮球'}}
console.log(user2);//{name: '法医', like: {eat: '面条', sport: '篮球'}}
console.log(user3);//{name: '法医', like: {eat: '面条', sport: '篮球'}}
user1[1].eat = "米饭";
console.log(user1);//{name: '前端猎手', like: {eat: '米饭', sport: '篮球'}}
console.log(user2);//{name: '法医', like: {eat: '米饭', sport: '篮球'}}
console.log(user3);//{name: '法医', like: {eat: '米饭', sport: '篮球'}}
5. jQuery 中的 $.extend
此方法可以实现深浅拷贝:
$.extend(deep, target, object1, object2, ...)
// deep: true 表示深拷贝 false 表示浅拷贝
// target: 要拷贝的目标对象
// object1: 待拷贝的对象
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
var user = {
name: "法医",
age: 18,
like: {
eat: "面条",
sport: "篮球",
},
};
var target = {};
$.extend(target, user);
target.name = "前端猎手";
console.log(user); //{name: '前端猎手', like: {eat: '面条', sport: '篮球'}}
console.log(target); //{name: '前端猎手', like: {eat: '面条', sport: '篮球'}}
</script>
</body>
如何实现 深拷贝
1. 最基本的方法
// 适用于属性较少的情况
var p1 = {
name:'jack',
age:12
}
var p2 = {
name: p1.name,
age: p1.age
};
2. 通用方法 Object.assign()
可对非嵌套对象进行深拷贝的方法
var p1 = {
name:'jack'
}
var p2 = {}
Object.assign(p2,p1); // 第一个参数为目的地 第二个参数为源头
console.log(p2); // {name:'jack'}
3. 用 JSON 序列化
把一个对象转换为 JSON 格式的字符串
不支持Date、正则、undefined、函数等数据;不支持引用;
var p1 = {
name:'jack',
age:12,
toy:{
name:'car'
}
}
// 序列化:把 JS 对象转换为 字符串
JSON.stringify(p1)
console.log(p1)
// '{"name:'jack',"age":12,"toy":{"name":"car"}}'
// 反序列化:把 JSON 格式的字符串转回 JS 对象
JSON.parse(JSON.stringify(p1))
4. 递归
递归、判断类型、检查环(嵌套)
var p1 = {
name:'jack',
age:12,
toy:{
name:'car'
}
}
var p2 = deepCopy({},p1);
p2.toy.name = 'plane';
console.log(p1) // ... name: 'car'
console.log(p2) // ... name: 'plane'
function deepCopy(dest, src){ // 形参分别为目标对象、源对象
let dest = dest || {}; // 容错处理,防止用户不传 dest 值
for(let key in src){
// 如果对象的属性又是对象,则递归处理
if (src.hasOwnProperty(key)) { // 防止拿到原型链属性
if(src[key] !== "null" && typeof src[key] === "object"){
dest[key] = (src[key].constructor === Array)?[]:{};
deepCopy(dest[key], src[key]);
} else {
dest[key] = src[key];
}
}
}
return dest;
}
闭包
闭包是JS的一种语法特性,一个语言可以选择是否支持闭包这个语法特性。
什么是闭包
- 闭包就是密闭的容器,用于存储数据。(存储数据的容器:变量、对象、数组、es6引入的set、map容器,分这么多类别是基于存储数据的结构不同)
- 闭包是一个特殊对象,存放数据的格式为
key:value
闭包形成的条件
- 函数嵌套
- 内部函数引用外部函数的局部变量
function f1(){
const a = 1;
return function(){
console.log(a); // 内部函数引用外部 f1 函数的局部变量 a
}
}
f1() // 外部函数调用
闭包的组成
由执行上下文(A)和在该执行上下文中创建的函数(B)两部分组成。
当B执行时,如果访问了A中变量对象中的值,那么闭包就会产生。
闭包的应用场景
function fun(){
const a = 1;
return function(){
console.log(a); // 内部 fun2 函数引用外部 fun 函数的局部变量 a
}
}
let fun2 = fun() // 外部函数调用
fun2()
这个内部函数可以访问外部函数作用域的变量,并且如果外部函数不暴露这个内部函数的话,那么外界就不知道这个内部函数的存在,只能在自己的内部使用,也就形成了一个私有的函数。
// 计算两个数的平方和
function squSum(a, b){
function squ(x){ // 内部函数单独负责计算一个数的平方
return x * x;
}
return squ(a) + squ(b);
}
console.log(squSum(2, 3)); // 13
- 内部函数也可以作为返回值返回出去,整个的外部函数就形成了一个高阶函数,即返回函数的一个函数。
function person(){
let name = "马云";
function getName(){
return name;
}
return getName;
}
var getName = person();
console.log(getName()); // 马云
- 上例的做法,等于给name设置了只读属性,外界只能访问他的值,而不能修改他的值,起到了保护作用,
person()即为高阶函数。
闭包的优点
延长外部函数局部变量的生命周期。通过闭包,我们可以在其他的执行上下文中,访问到函数的内部变量。
函数的执行上下文,在执行完毕之后,生命周期结束,那么该函数的执行上下文就会失去引用。其占用的内存空间很快就会被垃圾回收器释放。可是闭包的存在,会阻止这一过程。
闭包的缺点
使用不当容易造成内存泄露