1. Vue的响应式原理是什么?请详细说明Object.defineProperty()和Proxy的区别和用法。
响应式原理:Vue中采用了数据劫持的方式,通过Object.defineProperty()函数来监听数据变化,并在数据变化时触发对应的更新函数。 Object.defineProperty()与Proxy的区别:前者只能监听属性的读取和修改,后者可以监听数组的变化等更多场景,且性能更高。
// 实现observe函数,对data对象中的所有属性进行数据劫持
function observe(data) {
if (!data || typeof data !== 'object') {
return
}
Object.keys(data).forEach(key => {
defineReactive(data, key, data[key])
})
}
// 定义defineReactive函数,通过Object.defineProperty()函数来监听数据变化
function defineReactive(obj, key, val) {
observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
console.log('get value:', val)
return val
},
set: function reactiveSetter(newVal) {
console.log('set value:', newVal)
val = newVal
}
})
}
// 测试代码
const obj = { name: 'Tom', age: 18 }
observe(obj)
obj.age = 20
console.log(obj.age) // 输出:20
2. Vue的模板编译原理是什么?请说明它的优化策略和实现方式。并手动实现一个简单的模板编译器。
模板编译原理:Vue中将用户写好的模板转换成渲染函数,实际渲染时调用该函数进行渲染。模板编译主要包括三个阶段:解析、优化和生成。
优化策略:Vue在模板编译阶段会对模板进行静态节点标记和静态根节点标记,从而可以避免不必要的重复渲染和提升整体渲染性能。
实现方式:Vue通过将模板解析成抽象语法树(AST),再转换成render函数的方式来实现模板编译。最终生成的render函数就是一个虚拟DOM的描述对象,然后通过虚拟DOM的diff算法进行渲染更新。
// 简化版的 Vue 模板编译器
function compile(template) {
var element = document.createElement('div');
element.innerHTML = template;
Array.from(element.childNodes).forEach(function(node) {
if (node.nodeType === Node.TEXT_NODE) {
var reg = /\{\{(.+)\}\}/;
var match = node.textContent.match(reg);
if (match) {
var key = match[1].trim();
node.textContent = '{
{' + key + '}}';
node._key = key;
}
} else if (node.nodeType === Node.ELEMENT_NODE) {
Array.from(node.attributes).forEach(function(attr) {
if (attr.name.startsWith('v-')) {
if (att