从小白的角度读vue2.*源码一<使对象变的可观测>

214 阅读2分钟

前言

对于vue源码的解析 想必 是面试常考的了 对于一个 一年的小白笔者 也是被问到蒙圈 回答的只言片语 现在工作也渐渐稳定 一切向好 趁着脑子还没生锈 一步一步的开始 了解一下 当然了 这里只是第一篇 还会陆陆续续补上 一起加油吧 新时代的打工人。

介绍

<div id="app">
  {{ message }}
</div>
var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})

看起来这跟渲染一个字符串模板非常类似,但是 Vue 在背后做了大量工作

现在数据和 DOM 已经被建立了关联,所有东西都是响应式的

Vue最大的特点之一就是数据驱动视图,视图更新影响数据/数据更新影响视图 想要实现这个功能 就需要先弄明白 vue对data中的数据 都做了什么操作 本篇主要介绍一下是对对象怎么操作也就是怎么使用的Object.defineProperty方法;

Object.defineProperty

如果你不了解的话可以查看MDN关于Object.defineProperty的介绍

let data = {message:"hello word"}

image.png

比如我们定义了一个data对象 现在需要把他 变成 可观测的 我们可以 这样改写代码

let data = {}
let message = "hello word"
Object.defineProperty(data, 'message', {
  enumerable: true,
  configurable: true,
  get(){
    console.log('读取message')
    return message
  },
  set(newMessage){
    console.log('更新message')
    message = newMessage
  }
})

给属性添加了get,set方法 读取触发get() 写入触发set(新值)

读取:data.message --> 读取message

写入:data.message = 'vue' ---> 更新message

image.png

这样 一个对象就变的 可读 可写

核心源码

如果我们data中有很多属性 那就去 循环处理

所以可以改写上面的代码

class Observer {
  constructor(value) {
    this.value = value;
    if (Array.isArray(value)) {
      console.log("Array");
      // 如果是数组需要进行单独处理
    } else {
      this.walk(value);
    }
  }
  walk(obj) {
    const keys = Object.keys(obj);
    // 得到健名之后进行循环 调用 defineReactive方法
    for (let i = 0; i < keys.length; i++) {
      defineReactive(obj, keys[i]);
    }
  }
}
function defineReactive(
  obj, // data 数据
  key, // 当前执行的健名
  val
) {
  if (arguments.length === 2) {
    val = obj[key];
  }
  // 调用observe 方法 进行判断是否 深度添加 get()/set()
  observe();
  // 核心部分
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      console.log(`${key}属性被读取了`);
      return val;
    },
    set: function reactiveSetter(newVal) {
      if (val === newVal) {
        return;
      }
      console.log(`${key}属性被修改了`);
      val = newVal;
    },
  });
}
function observe(value) {
  // 如果是对象就 递归调用 
  if (isPlainObject(value)) {
    new Observer(value);
  }
}

function isPlainObject(value) {
  return Object.prototype.toString.call(value) === "[object Object]";
}

let data = {
  platform: "掘金",
  author: 'Wandou',
  date: {
    checkTime: "2021-9-3",
  },
};

new Observer(data);

这样 最简单的 一个 数据监听 就实现了

源码:/src/core/observer/index.js 如果 你有精力 可以查看 一下源码 你会发现 上面我们改写的代码 跟 vue源码的执行逻辑 是一样的 这里只是一个示例 还有 添加Dep队列 判断是否已经进行监听 ....

总结

感谢您能读到最后!

╔¿┬δ_╦╤╦≈┴¬║╧┤½▓Ñ╤∙╩╜-▒Ω╫╝╔½░µ.png

一起加油吧~

参考文档:

Vue源码系列-Vue中文社区

尤大大带你读源码