1. 箭头函数和function的区别
2. bind、call、apply 区别
call:第一个参数是指定函数运行时的this指向,后面的参数是传递给函数的参数,参数以逗号,隔开。
function greet(c1, c2) {
// 在这个方法中this因为指向了person,所以this.name = Tom,而C1和c2为传入的参数,也就是call参数有几个就是几个
console.log(`Hello, I am ${this.name}, I love ${c1} and ${c2}`);
}
let person = { name: 'Tom' };
greet.call(person, 'apple', 'banana');// 这里this指向了person
apply:第一个参数也是指定函数运行时的this指向,与call不同,apply第二个参数是一个数组,数组中的元素被用作函数的参数。
function greet(c1, c2) {
// 因为person指向了this,所以this.name 也是Tom,但是c1和c2是传入的数组的值,也就是说第二个参数必须是数组
console.log(`Hello, I am ${this.name}, I love ${c1} and ${c2}`);
}
let person = { name: "Tom" };
greet.apply(person, ["apple",'orage'], ["banna"]);// 这里this 指向了person,
bind:bind方法返回一个新的函数,其this值被绑定到你指定的对象。bind方法并不立即执行函数,而是返回一个改变了this指向的新函数。
function greet(c1, c2) {
// 参数和call的参数一样,都是一个一个传入
console.log(`Hello, I am ${this.name}, I love ${c1} and ${c2}`);
}
let person = { name: "Tom" };
let greetPerson = greet.bind(person, "apple", "banana");// this 指向了person,但是bind返回的是一个新的方法,因此不会立即执行。
greetPerson(); // Hello, I am Tom, I love apple and banana
3. this的作用域和使用场景
①普通函数的调用,this指向的是window
②对象方法的调用,this指的是该对象,且是最近的对象
③构造函数的调用,this指的是实例化的新对象
④apply和call调用,this指向参数中的对象
⑤匿名函数的调用,this指向的是全局对象window
⑥定时器中的调用,this指向的是全局变量window
⑦.箭头函数被非箭头函数包含,则this绑定的是最近一层非箭头函数的this,否则this的值则被设置为全局对象
⑧.onclick和addEventerListener是指向绑定事件的元素(ev.currentTarget)
4. 闭包的作用,和使用场景
5. 防抖和节流
二者区别:
- 防抖就是排队阻塞,你是一个强盗,你说10:00吃饭,但是前面排队的人9:59到了,但是你来了,你就要大家一起和你等到10:00才可以吃饭。
- 节流就是等待有票,大家去医院挂号,本来是按照顺序挂号,但是你们来早了,7:00才放票,那么7点以前来的都要排队等待一起抢号。
- 定义防抖, 就是一段时间内只让执行一次操作,如果在这个时间内已经有任务在执行,那么就取消重新计时。
// 防抖
const debounce = (fn, delay) => {
console.log(this, "lxz");
var timer = null;
return function (...args) {
// 如果定时任务执行完毕那么timer就消失了,所以就重新定义timer,如果timer依然存在,那么说明上次执行还没有结束,因此需要重新计时,
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
// 方法1:使用闭包函数中的参数
fn(...args);
// 方法2:使用this绑定隐形参数, this 就是当前对象,arguments 就是当前的所有参数
fn.apply(this, arguments); //this和参数
timer = null;
}, delay);
};
};
// 调用方法
// 获取对象
const app = document.querySelector("#app");
// 设置输入事件监听/
// 在500秒内执行一次数据输入
app.addEventListener(
"input",
// 实名调用
debounce((e) => {
console.log("数据发送成功", e.target.value);
}, 500)
// debounce()
);
- 定义节流 如果用户不停的触发某种动作,那么在一段时间内就执行一次,如果用户只执行一次,那就获取当前执行时间点内的结果,也就说我们要延迟用户行为
函数定义
function throttle(fn, interval) {
// 1. 记录上一次的开始时间
let lastTime = 0;
return function (e) {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime();
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
const remainTime = interval - (nowTime - lastTime);
if (remainTime <= 0) {
// 2.3真正触发函数
fn(e); //做出响应
// 2.4保留上次触发的时间
lastTime = nowTime; //更新最后一次执行的时间
}
};
}
函数调用
// 定义监听事件
const inputEl = document.querySelector("#app");
let counter = 0;
const inputChange = function (event) {
console.log(`发送了第${++counter}次网络请求`, this, event.target.value);
};
// 节流处理
inputEl.oninput = throttle(inputChange, 2000); //当用户不断触发事件按照2秒的频率执行
6. v-modle 原理设计
其实就是利用Object.defineProperty 进行数据拦截,利用其get,set方法进行数据赋值
<div id="username"></div>
<input type="text" id="app">
<script>
let obj ={}
Object.defineProperty(obj,"username",{
get(){
return "1"
},
set(val){
document.querySelector("#username").innerHTML = val
}
})
document.getElementById("app").addEventListener('input',(e)=>{
obj.username = e.target.value
})
</script>
7、订阅发布模式
订阅模型 思路:创建一个dep对象,其中包含多有订阅者,注册方法,通知订阅者的方法
8. vue的插槽
1、具名插槽 传入
<lxz-header-item :name="i" v-for="i in 10" :key="i"></lxz-header-item>
<div slot="headername">DTM2112</div>
</lxz-header>
接收
<div class="slot">
// 实名
<slot name="headername"></slot>
// 匿名
<slot></slot>
</div>
9、 计算属性是否可以被修改
computed: {
// 普通设置计算属性
double1() {
return this.count * 2;
},
// 如果计算属性可以被修改,那么需要设置set和get方法。比如被v-modle所引用
double: {
set(val) {
this.count = this.count * val;
},
get() {
return this.count * 3;
},
},
},
10、 watch 进行监听,如果是上引用类型监听,那么需要进行深度监听,另外无法监听到变化前的值
// 数据改变引用类型内部的数据,执行这个方法会引起下面stu的变化,但是newData和old是同样的数据,都是改变以后的
updateStu() {
this.stu.person = {
name: 5343,
age: 343,
};
},
// 进行数据的深度监听
stu: {
handler(newData, old) {
this.watchOldStu = old;
this.watchNewStu = newData;
},
deep: true,
},
11、 什么事自定义v-model
v-modle语法糖,实际上就是两个指令的集合 value 值的传递,自组件接受value就可以获取到对应的值 input 事件回调,实际上就是父组件给自组件传递了一个input事件,只要在值发生变化的时候回调这个方法就可以
12、 proxy的原理
``
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>vue3数据监听</title>
</head>
<body>
<script>
function isObject(obj) {
return obj !== null && typeof obj === "object";
}
function reactive(obj) {
if (!isObject(obj)) {
return obj;
}
const proxy = new Proxy(obj, {
get(target, key) {
console.log("获取数据", target[key]);
if (isObject(target[key])) {
return reactive(target[key]);
} else {
return Reflect.get(target, key);
}
},
set(target, key, value) {
console.log("设置数据", target[key], value);
target[key] = value;
Reflect.set(target, key, value);
},
deleteProperty(target, key) {
console.log(target, key);
return Reflect.deleteProperty(target, key);
},
});
return proxy;
}
const data = {
name: "lxz",
age: 12,
info: { a: { b: { c: { d: 1 } } } },
};
const proxyData = reactive(data);
proxyData.name;
proxyData.name = 121;
delete proxyData.name;
console.log(proxyData.name);
delete proxyData.info.a.b.c;
</script>
</body>
</html>
13、 vue3为什么比vue2快
6-19可以参考
14、什么是高级函数,
15、reactDom中的CreateProtal,渲染到对应元素的外部
16、 react context ,公共信息的主题颜色createContext
17、父组件更新以后,子组件是否需要重新渲染
18、scu的使用,为什么需要不变值进行处理
19、hoc组件增加,render props 作为插槽处理
20、纯函数的定义和原理
21 JSX的本质是什么,vue的本质是什么
22、 vue和react如何吧vnode渲染成真实的dom
23、 react性能优化
- 1、渲染使用key
- 2、事件销毁,定时任务销毁
- 3、异步组件的使用
- 4、合理使用bind this 次数
- 5、scu的合理使用
- 6、不可变值的性能处理
- 7、webpack优化
- 8、图片懒加载
- 9、使用ssr
- 10、
24、vue和react的区别
- 共同点:
- 支持组件化
- 数据驱动视图
- vdom操作dom
- 不同
- vue模版 react是jsx 爱的不同
- vue声明编程,数据都在data中提前声明,react函数编程setState利用方法来更新
- vue指令比较全面,react自己来做
25、打包构建发布webpack
优化构建打包
- 生成环境
- 优化babel-loader:缓存,排除不需要的nodemodle,压缩
- ignorePlugin 排除代码体积
- noParse不引用资源
- happyPack 多进程打包
- paralleIUglifyPlugin 多进程压缩js
- 开发环境 自动刷新,热更新,DllPlugin开发环境打包
产出代码
体积减小,合理分包,不重复加载速度更快,内存使用更少
-
图片压缩
-
bunle+hash值
-
懒加载
-
提取公共代码 cache split chunks
-
使用cdn加速
-
环境设置prod,dev,代码压缩
-
tree-shaking 代码