手写Vue2核心原理(二)

生命周期的合并

源码地址:gitee源码地址

1.Mixin原理

import { mergeOptions } from '../utils/index';

export function initGlobalApi(Vue) {
    //> 源码:Vue.options = {created:[a,b,c],watch:[a,b,c]}
    Vue.options = {};
    Vue.Mixin = function (mixin) {
        // 对象的合并
        this.options = mergeOptions(this.options, mixin);
    };
}

2.合并生命周期

export const HOOKS = ['beforeCreate', 'created', 'beforeMount', 'mounted', 'beforeUpdate', 'updated', 'beforeDestroy', 'destroyed'];
export function mergeOptions(parent, child) {
    //> Vue.options = {created:[a,b,c],watch:[a,b,c]}
    const options = {};

    let starts = {};
    starts.data = function (parentVal, childVal) {
        return childVal;
    };
    starts.watch = function () {};
    starts.methods = function () {};
    starts.computed = function () {};

    // 遍历生命周期
    HOOKS.forEach((key) => {
        starts[key] = mergeHooks;
    });

    function mergeHooks(parentVal, childVal) {
        //> 判断是否有父或子
        if (childVal) {
            if (parentVal) {
                return parentVal.concat(childVal);
            }
            return [childVal];
        } else {
            return [parentVal];
        }
    }
    for (const key in parent) {
        mergeField(key);
    }
    for (const key in child) {
        mergeField(key);
    }
    function mergeField(key) {
        // 根据key 采用策略模式
        if (starts[key]) {
            options[key] = starts[key](parent[key], child[key]);
        } else {
            options[key] = child[key];
        }
    }
    return options;
}

4.调用生命周期

export function callHook(vm, hook) {
    const handlers = vm.$options[hook];
    if (handlers) {
        for (let i = 0; i < handlers.length; i++) {
            handlers[i].call(vm);
        }
    }
}

5.初始化流程中调用生命周期

Vue.prototype._init = function (options) {
    const vm = this;
    vm.$options = mergeOptions(vm.constructor.options,options);
    // 初始化状态
    callHook(vm,'beforeCreate');
    initState(vm);
    callHook(vm,'created');
    if (vm.$options.el) {
    	vm.$mount(vm.$options.el);
    }
}
### Vue2Vue3 响应式原理的区别与实现方式 #### Vue2 响应式原理 Vue2 的响应式系统主要依赖于 `Object.defineProperty` 方法。该方法允许开发者定义对象的 getter 和 setter,从而在数据被访问或修改时触发相应的回调函数。 以下是 Vue2 响应式的几个关键点: - **核心机制**: 使用 `Object.defineProperty` 劫持对象属性的读写操作[^3]。 - **初始化过程**: 在组件实例化过程中,如果存在 `data` 属性,则会调用 `initData(vm)` 函数对其进行递归遍历并转换为响应式对象[^4]。 - **局限性**: - **无法监听数组变化**: JavaScript 对象的操作(如直接通过索引赋值或改变数组长度)不会触发响应式更新。 - **新增属性不可监听**: 如果向已有的对象中动态添加新属性,默认情况下这些属性不会成为响应式的一部分。 - **性能瓶颈**: 对于深层嵌套的对象结构,需要逐层递归地将其转化为响应式对象,这可能导致较大的计算开销。 #### Vue3 响应式原理 Vue3 改进了原有的响应式设计,采用了更现代的 ES6 特性——`Proxy` 来替代 `Object.defineProperty`。这种新的实现方式带来了显著的功能增强和性能提升。 以下是 Vue3 响应式的几个重要特性: - **核心机制**: 利用 `Proxy` 拦截目标对象的行为,支持更多类型的拦截操作,例如获取 (`get`)、设置 (`set`)、删除 (`deleteProperty`) 等[^1]。 - **优势**: - **全面监听**: 不仅能够监控已有属性的变化,还能自动捕获新增或删除属性的情况[^2]。 - **嵌套代理**: 自动递归处理复杂的数据结构,无需手动干预即可完成深层次对象的响应式转化。 - **高效依赖管理**: 结合 `WeakMap` 和 `Set` 数据结构,精确记录观察者及其关联的依赖关系,减少冗余计算。 - **按需激活**: 只有当某个属性真正被访问或者更改时才会触发生命周期钩子,降低了整体运行成本。 #### Proxy vs Object.defineProperty | 特性 | Object.defineProperty (Vue2) | Proxy (Vue3) | |--------------------------|-----------------------------------------------------|--------------------------------------------------| | **适用范围** | 仅限于对象属性 | 能够覆盖整个对象以及其内部的所有操作 | | **新增属性的支持** | 需要显式调用 `Vue.set()` 或重新注册 | 自动生成响应式 | | **数组变更检测能力** | 存在盲区 | 完全兼容各种形式的数组操作 | | **性能表现** | 初始化阶段可能较慢 | 更加轻量化 | ```javascript // Vue2 示例:使用 Object.defineProperty 实现简单响应式 function defineReactive(obj, key, val) { Object.defineProperty(obj, key, { get() { console.log(`Getting value of ${key}`); return val; }, set(newVal) { if (newVal !== val) { console.log(`Setting new value to ${key}:`, newVal); val = newVal; } } }); } const obj = {}; defineReactive(obj, 'name', 'John'); obj.name; // 输出: Getting value of name obj.name = 'Doe'; // 输出: Setting new value to name: Doe // Vue3 示例:使用 Proxy 实现高级响应式 const handler = { get(target, propKey, receiver) { console.log(`Accessing property "${propKey}"`); return Reflect.get(target, propKey, receiver); }, set(target, propKey, value, receiver) { console.log(`Updating property "${propKey}" with value "${value}"`); return Reflect.set(target, propKey, value, receiver); } }; const targetObj = {}; const proxyObj = new Proxy(targetObj, handler); proxyObj.greeting = 'Hello'; console.log(proxyObj.greeting); // Accessing property "greeting" ``` #### 总结 相较于 Vue2 的 `Object.defineProperty` 方案,Vue3 所采用的 `Proxy` 技术不仅扩展了功能边界,还极大地提升了开发体验与应用效率。它解决了旧版框架中存在的诸多痛点问题,使得前端工程师可以更加专注于业务逻辑本身而非底层细节。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龟中的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值