当前位置: 首页 > article >正文

第1章 Vue设计哲学(深度解析版)

1.1 声明式编程 vs 命令式编程

案例对比分析

传统命令式实现:

// 创建元素
const div = document.createElement('div')

// 设置属性(命令式操作)
div.id = 'counter'
div.textContent = '0'

// 挂载到DOM
document.body.appendChild(div)

// 更新逻辑(必须手动操作DOM)
setTimeout(() => {
  div.textContent = '1' // 显式指定如何更新
}, 1000)

Vue声明式实现:

<div id="app">{{ count }}</div>

<script>
new Vue({
  el: '#app',
  data: { count: 0 },
  mounted() {
    setTimeout(() => {
      this.count = 1 // 只需关心数据变化
    }, 1000)
  }
})
</script>

关键差异解析

维度命令式声明式
关注点如何做(How)做什么(What)
DOM操作开发者直接操作框架自动处理
代码量与复杂度正相关保持简洁
维护性需要跟踪每个状态变化数据驱动自动更新

设计哲学体现

// Vue内部处理流程示意图
数据变化 → 触发setter → 通知Watcher → 
生成新VDOM → Diff算法 → 精准更新DOM

1.2 响应式系统核心实现

1.2.1 数据劫持原理

代码实现:

function defineReactive(obj, key, val) {
  const dep = new Dep() // 每个属性对应一个依赖管理器
  
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      if (Dep.target) {        // 存在当前Watcher时
        dep.depend()           // 建立依赖关系
      }
      return val
    },
    set: function reactiveSetter(newVal) {
      if (newVal === val) return
      val = newVal            // 更新内部值
      dep.notify()            // 通知所有订阅者
    }
  })
}

关键代码解析:

  1. Dep 类:依赖管理器

    • 每个响应式属性对应一个 Dep 实例
    • 负责收集依赖(Watcher)和通知更新
  2. defineProperty 的作用:

    • 拦截操作:在属性被访问和修改时执行自定义逻辑
    • 内存管理:通过闭包维护内部值 val
  3. Dep.target 机制:

    • 全局唯一变量,指向当前正在计算的 Watcher
    • 保证依赖收集的正确性

1.2.2 完整的依赖收集流程

Watcher类核心代码:

class Watcher {
  constructor(vm, expOrFn, cb) {
    this.vm = vm           // Vue实例
    this.cb = cb           // 回调函数
    this.getter = parsePath(expOrFn) // 路径解析器
    this.value = this.get() // 初始获取值
  }

  get() {
    Dep.target = this     // 标记当前Watcher
    let value
    try {
      value = this.getter.call(this.vm, this.vm) // 触发getter
    } finally {
      Dep.target = null   // 收集完成后重置
    }
    return value
  }

  update() {
    this.run()           // 触发回调
  }

  run() {
    const value = this.get()
    if (value !== this.value) {
      const oldValue = this.value
      this.value = value
      this.cb.call(this.vm, value, oldValue) // 执行回调
    }
  }
}

执行流程解析:

  1. 初始化阶段

    • 创建 Watcher 实例时立即调用 get()
    • 设置 Dep.target = 当前Watcher
    • 执行 getter 函数触发数据属性的 get 拦截器
  2. 依赖收集阶段

    • 在数据属性的 get 中调用 dep.depend()
    • 将当前 Watcher 添加到 Dep 的订阅列表
  3. 更新阶段

    • 数据变化触发 set 拦截器
    • 调用 dep.notify() 遍历执行所有 Watcher 的 update()
    • 执行回调函数完成视图更新

1.2.3 数组的特殊处理

代码示例:

const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)

;['push', 'pop', 'shift'].forEach(method => {
  const original = arrayProto[method]
  
  def(arrayMethods, method, function mutator(...args) {
    const result = original.apply(this, args) // 调用原生方法
    const ob = this.__ob__                 // 获取Observer实例
    ob.dep.notify()                        // 手动触发通知
    return result
  })
})

关键点说明:

  1. 原型链继承:创建继承自Array原型的对象
  2. 方法重写:对变异方法进行拦截
  3. 手动通知:在数组变化后主动触发依赖更新
  4. 实现原理
    arr.__proto__ = arrayMethods // 修改数组原型链
    

1.3 模板编译深度解析

1.3.1 编译过程三个阶段

示例模板:

<div v-if="show">
  <span>{{ message }}</span>
</div>
阶段一:解析(Parse)

输出AST结构:

{
  type: 1,
  tag: 'div',
  attrsList: [{ name: 'v-if', value: 'show' }],
  directives: [{ name: 'if', rawName: 'v-if', value: 'show' }],
  children: [{
    type: 1,
    tag: 'span',
    children: [{
      type: 2,
      expression: '_s(message)',
      text: '{{ message }}'
    }]
  }]
}

解析过程关键点:

  • 使用正则表达式匹配标签/属性/指令
  • 构建树形结构的AST节点
  • 记录标签之间的父子关系
阶段二:优化(Optimize)

静态标记结果:

{
  // ...其他属性
  static: false,
  children: [{
    static: false,
    children: [{
      static: false // 包含动态插值表达式
    }]
  }]
}

优化策略:

  1. 标记静态节点(无动态绑定)
  2. 标记静态根节点(子树全静态)
  3. 提升静态节点(复用VNode)
阶段三:生成(Generate)

生成的Render函数:

function render() {
  with(this){
    return (show) ? 
      _c('div', [_c('span', [_v(_s(message))])]) 
      : _e()
  }
}

关键函数说明:

  • _c: createElement(创建VNode)
  • _v: createTextVNode(创建文本节点)
  • _s: toString(转换为字符串)
  • _e: createEmptyVNode(创建空节点)

1.4 初始化流程全解析

1.4.1 new Vue() 的执行轨迹

function Vue(options) {
  this._init(options) // 入口方法
}

Vue.prototype._init = function(options) {
  // 合并选项
  vm.$options = mergeOptions(...)
  
  initLifecycle(vm)   // 初始化生命周期
  initEvents(vm)      // 初始化事件系统
  initRender(vm)      // 初始化渲染函数
  callHook(vm, 'beforeCreate')
  
  initInjections(vm)  // 处理inject
  initState(vm)       // 核心:初始化响应式系统
  initProvide(vm)     // 处理provide
  callHook(vm, 'created')
  
  if (vm.$options.el) {
    vm.$mount(vm.$options.el) // 开始挂载
  }
}

关键初始化步骤说明:

  1. 选项合并

    • 合并全局配置和实例配置
    • 处理组件继承关系
  2. initState 核心作用

    function initState(vm) {
      if (opts.props) initProps(vm, opts.props)    // 初始化Props
      if (opts.methods) initMethods(vm, opts.methods) // 处理methods
      if (opts.data) initData(vm)                  // 响应式处理data
      if (opts.computed) initComputed(vm, opts.computed) // 处理计算属性
      if (opts.watch) initWatch(vm, opts.watch)    // 处理侦听器
    }
    
  3. 生命周期钩子调用时机

    钩子阶段触发时机
    beforeCreate初始化inject/provide之前
    created完成响应式处理,未挂载DOM

1.5 常见问题解析

Q1:为什么data必须是函数?

错误示例:

// 组件选项
data: { count: 0 } // 多个实例会共享同一数据对象

正确写法:

data() {
  return { count: 0 } // 每次实例化返回新对象
}

原理说明:

  • 组件可能被多次实例化
  • 函数形式保证每个实例都有独立的数据副本

Q2:Vue如何检测数组变化?

  • 无法检测 的情况:

    vm.items[0] = newItem // 索引直接赋值
    vm.items.length = 2   // 修改length
    
  • 正确方式

    Vue.set(vm.items, 0, newItem)
    vm.items.splice(0, 1, newItem)
    

实现原理:

  1. 重写数组变异方法
  2. 对新增元素进行响应式处理
  3. 手动触发依赖通知

http://www.kler.cn/a/558857.html

相关文章:

  • ReACT agent和FC agent
  • 纯CPU跑DeepSeek-R1 671b大模型
  • Pytorch深度学习教程_5_编写第一个神经网络
  • windows下安装CUDA-本地微调大模型
  • JUC并发—11.线程池源码分析
  • 通过Hive小文件合并(CombineHiveInputFormat)减少80%的Map任务数
  • w803|联盛德|WM IoT SDK2.X测试|window11|VSCODE|(4):IDE配置
  • 解决Open WebU无法显示基于OpenAI API接口的推理内容的问题
  • 【开源项目】分布式文本多语言翻译存储平台
  • 关于Python的一些基础知识(太阳太阳,持续更新)
  • 【DeepSeek-R1】写了个DeepSeek-R1本地软件,欢迎参与测试
  • 使用ESP-IDF来驱动INMP441全向麦克风
  • Redis 如何实现消息队列?
  • Python|OpenCV-实现人物眨眼检测(21)
  • 《从GPT-4到“东数西算”:AI算力的全球格局与技术趋势》
  • 五、Three.js顶点UV坐标、纹理贴图
  • 算法与数据结构(旋转链表)
  • (四)趣学设计模式 之 原型模式!
  • YOLOv12:以注意力为中心的物体检测
  • Servlet 国际化