# vue-source **Repository Path**: longdog/vue-source ## Basic Information - **Project Name**: vue-source - **Description**: vue源码学习 - **Primary Language**: NodeJS - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-05-06 - **Last Updated**: 2024-06-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # vue源码学习 ## 配置rollup 何为rollup? 打包工具。 配置 ```javascript import { babel } from "@rollup/plugin-babel"; import serve from "rollup-plugin-serve"; export default { input: "src/index.js", output: { file: "public/vue.js", format: "umd", name: "Vue", sourcemap: true, }, plugins: [ // 高级语法转成通用语法 babel({ babelHelpers: "bundled", exclude: "node_modules/**" }), // 打包后启动web服务 serve({ open: true, contentBase: "public", openPage: "", port: 3000, }), ], }; ``` ## 初始化data并拦截 ### instance目录 #### 作用 该目录为Vue初始化相关的代码,也就是说调用new Vue时创建Vue实例时做的一些事情,包括:data、computer、props等数据的初始化。 #### this._init() 实例化调用的是这个方法:`this._init()`,而这个方法来自initMixin方法挂在在原型上。 真正处理实例化的是`this._init()`方法内部,以init开头的方法,比如`initState()`处理的就是data初始化、`initProps`处理的是props的初始化,等等... 为了代码的可维护性,以init开头的方法,都是以单独的一个文件存于instance目录下,比如`state.js`对应的就是`initState()`方法的内容。 #### initState() data的初始化做的就是数据的响应式。具体到该方法内部的`observe()`方法就是干这个事的,而这个方法借助了observer目录下的代码,下一节来分析。 ### observer目录 #### 作用 处理响应式的代码基本都存于这个目录。 #### Observer类 该类负责了响应式的主要工作。 在其构造方法中,会判断是数组还是对象。如果是对象则通过**Object.defineProperty定义get和set**进行响应式拦截;如果是数组通过**重写数组方法**来拦截。 由于data中会存在多层次的数据,比如对象内对象,数组内对象等,所以源码中使用了一些**递归方法**。 举例:在`defineReactive()`方法内,他会判断元素值是什么类型,然后递归调用`defineReactive()`方法。 ```javascript import { arrayMethods } from "./array.js"; export class Observer { constructor(value) { if (Array.isArray(value)) { value.__proto__ = arrayMethods; this.observeArray(value); } else { this.walk(value); } } walk(obj) { const keys = Object.keys(obj); for (let i = 0; i < keys.length; i++) { defineReactive(obj, keys[i]); } } observeArray(arr) { for (let i = 0; i < arr.length; i++) { observe(arr[i]); } } } function defineReactive(obj, key) { let value = obj[key]; // 如果元素值为对象,那么需要递归处理。这里不需要判断是否为对象,因为在observe方法内已经判断了 observe(value); Object.defineProperty(obj, key, { get() { console.log("getting value:" + value); return value; }, set(newVal) { console.log("setting newVal:" + newVal); value = newVal; }, }); } export function observe(value) { if (typeof value !== "object") { return; } return new Observer(value); } ``` 重写数组方法需要注意不能覆盖元素的数组方法,需要借助一个代理对象。 ```javascript const originArrayMethods = Array.prototype; export const arrayMethods = Object.create(originArrayMethods); ["push", "pop", "shift", "unshift", "splice", "sort", "reverse"].forEach( function (method) { const original = originArrayMethods[method]; Object.defineProperty(arrayMethods, method, { // 这里一定要用function,不能用箭头函数,用function时this绑定运行时的对象,而用箭头函数this为Object,会报错 value: function (...arg) { console.log("执行 " + method); return original.apply(this, arg); }, }); } ); ```