发布于 2024 年 2 月 26 日,星期一
前端面试题的时效性和热度,强调了面试题的更新速度和紧跟技术趋势的重要性。它暗示了前端开发者需要不断学习新知识,以应对快速变化的技术环境。同时,标题中的“昨天”一词突出了信息的即时性,提醒读者关注最新的技术动态和面试要求,避免使用过时的知识。这种标题反映了前端领域的竞争激烈和技术迭代迅速,要求从业者保持敏锐的洞察力和持续学习的态度。
系列首发于公众号『非同质前端札记』https://mp.weixin.qq.com/s?__biz=MzkyOTI2MzE0MQ==&mid=2247485576&idx=1&sn=5ddfe93f427f05f5d126dead859d0dc8&chksm=c20d73c2f57afad4bbea380dfa1bcc15367a4cc06bf5dd0603100e8bd7bb317009fa65442cdb&token=1071012447&lang=zh_CN#rd ,若不想错过更多精彩内容,请“星标”一下,敬请关注公众号最新消息。
vue2
:
Vue2
中注意使用 Object.defineProperty()
方法来实现响应式,它为对象中的每一个属性都定义了一个 getter
和 setter
,当数据发生变化时,会触发相应的更新操作,从而让视图也随之更新。Vue2
中,数据对象通过 new Vue
中的 data
对象进行实例化,在实例化的过程中,Vue
会遍历这个数据对象使用 Object.defineProperty()
把他们转化为 getter/setter
,当 getter/setter
接收到访问或修改时,会通过对应的 Watcher
及所依赖的 Watcher
进行更新。vue3
:
Reactive API
和 Proxy
来实现响应式reactive()
函数会讲一个普通对象转换成响应式对象,这个函数内部使用了 ES6
的 proxy
对象,讲的对象的 getter/setter
, 并使用依赖收集,派发更新等机制。ref
和 computed
这两个响应式 API
,让我们可更灵活的管理组件内的数据状态。Object.defineProperty()
做一些拦截操作const arrayProto = Array.prototype // 获取Array的原型
function def (obj, key) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
value: function(...args) {
console.log(key); // 控制台输出 push
console.log(args); // 控制台输出 [Array(2), 7, "hello!"]
// 获取原生的方法
let original = arrayProto[key];
// 将开发者的参数传给原生的方法,保证数组按照开发者的想法被改变
const result = original.apply(this, args);
// do something 比如通知Vue视图进行更新
console.log('我的数据被改变了,视图该更新啦');
this.text = 'hello Vue';
return result;
}
});
}
// 新的原型
let obj = {
push() {}
}
// 重写赋值
def(obj, 'push');
let arr = [0];
// 原型的指向重写
arr.__proto__ = obj;
// 执行push
arr.push([1, 2], 7, 'hello!');
console.log(arr);
getter/setter
来实现响应式,没有对数组的每个键设置响应式,而是直接对值递归设置响应式。主要考虑到性能问题。Math.floor
将坐标强制转换为整数。lineWidth
设置为整数值<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vue2数据劫持Demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 在这个demo中,我们首先创建了一个Vue实例,然后在mounted钩子函数中,遍历data对象的所有属性,并使用defineReactive方法来对每个属性进行数据劫持。在defineReactive方法中,我们使用Object.defineProperty方法来重新定义属性的set和get方法。在set方法中,我们实现了自己的逻辑,例如在属性变化时强制更新视图。
接下来,我们在页面中展示了data中的一个属性message,并提供了一个按钮,点击按钮时会修改message属性的值。当message属性发生变化时,会触发我们自定义的set方法,从而实现了数据的响应式更新。
需要注意的是,在这个demo中我们使用了Vue的forceUpdate方法来强制更新视图。这个方法会强制vue 重新渲染视图,从而显示最新的数据。虽然这个方法可以解决数据更新不及时的问题,但是它会导致性能上的一些损失。因此,在实际开发中,我们应该尽量减少使用
forceUpdate方法,而是通过合理的设计数据结构来避免这个问题。 -->
<p>{{ message }}</p>
<button @click="changeMessage">Change Message</button>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
message: "Hello world!",
},
mounted: function () {
var self = this;
Object.keys(this.$data).forEach(function (key) {
self.defineReactive(self.$data, key, self.$data[key]);
});
},
methods: {
defineReactive: function (obj, key, val) {
var self = this;
Object.defineProperty(obj, key, {
get: function () {
console.log("get " + key + ": " + val);
return val;
},
set: function (newVal) {
console.log("set " + key + ": " + newVal);
val = newVal;
self.$forceUpdate(); // 强制更新视图
},
});
},
changeMessage: function () {
this.message = "Hello Vue!";
},
},
});
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vue3数据劫持Demo</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
<!-- 在这个demo中,我们首先创建了一个data对象,其中包含一个属性message。然后,我们使用Proxy方法创建了一个名为reactiveData的代理对象,并在set方法中添加了自定义的逻辑。在这个demo中,我们只是简单地在控制台中输出了一些调试信息,但是在实际开发中,我们可以在set方法中添加任何我们需要执行的逻辑,例如更新视图或向服务器发送请求等。
接下来,我们使用Vue.createApp方法创建了一个Vue实例,并将reactiveData对象作为data选项传递给它。这样,我们就实现了对data对象中属性的监听。在页面中展示了data中的一个属性message,并提供了一个按钮,点击按钮时会修改message属性的值。当message属性发生变化时,会触发我们自定义的set方法,从而实现了数据的响应式更新。
需要注意的是,在这个demo中我们没有使用$forceUpdate方法来强制更新视图。这是因为Vue3中的数据响应式系统已经得到了优化,并且可以更好地处理数据更新的问题,因此我们不再需要手动强制更新视图。 -->
<p>{{ message }}</p>
<button @click="changeMessage">Change Message</button>
</div>
<script>
const data = {
message: "Hello world!",
};
const reactiveData = new Proxy(data, {
set(target, key, value) {
console.log(`set \${key}: \${value}`);
target[key] = value;
return true;
},
});
const app = Vue.createApp({
data() {
return reactiveData;
},
methods: {
changeMessage() {
this.message = "Hello Vue!";
},
},
});
app.mount("#app");
</script>
</body>
</html>
let originalArr = [{name: 'John', age: 26}, {name: 'Mary', age: 22}, {name: 'Peter', age: 28}];
let filterArr = [{name: 'John', age: 26}, {name: 'Bob', age: 25}];
let filteredOriginalArr = originalArr.filter((obj) => {
return !filterArr.map((item) => item.name).includes(obj.name);
});
console.log(filteredOriginalArr); // Output: [{name: 'Mary', age: 22}, {name: 'Peter', age: 28}]
// originalArr 表示要被筛选的对象数组
// filterArr 则是用来进行筛选的参照数组
// filter 方法将会按条件对 originalArr 进行筛选,并返回结果存储在 filteredOriginalArr 中。
Q:(question)
R:(result)
A:(attention matters)
D:(detail info)
S:(summary)
Ana:(analysis)
T:(tips)