【vue】响应式(object.defineProperty)、可配置的参数、vue渲染机制

Vue 2的响应式原理主要是基于Object.defineProperty来实现的。

  1. 数据劫持

    • 当一个Vue实例被创建时,它会遍历data选项中的所有属性。对于每个属性,使用Object.defineProperty来进行数据劫持。这个方法允许精确地定义一个对象的属性,包括属性的值、可枚举性、可配置性和可写性。
    • 重点是定义了属性的getset函数。get函数用于获取属性的值,在这个函数内部可以进行一些依赖收集的操作。例如,当模板中使用了这个属性,就会在get被调用时,将这个模板中的使用点(watcher)收集起来。set函数用于设置属性的值,当属性的值被修改时,set函数会被触发。在set函数内部,会通知之前收集到的所有依赖(watcher)进行更新,从而实现数据变化到视图更新的过程。
  2. 依赖收集和通知更新(Watcher和Dep)

    • Dep(Dependency):可以看作是一个依赖收集器,是一个发布者。它主要用于收集依赖(watcher),在数据劫持的get中,会将当前的watcher添加到Dep实例中。每个响应式数据都会有一个对应的Dep实例。
    • Watcher:是一个订阅者,主要用于观察数据的变化。它可以是一个组件渲染的观察者,也可以是一个用户自定义的计算属性的观察者等。当数据发生变化时,Dep会通知所有订阅了它的WatcherWatcher收到通知后,会执行相应的更新操作,如更新组件的DOM节点,重新计算计算属性的值等。

简单来说,当数据发生变化时,通过set触发Dep发布消息,Watcher收到消息后更新视图,而视图中的数据绑定表达式被解析时,会触发get进行依赖收集,这就实现了数据和视图之间的响应式绑定。

Object.defineProperty()方法中,用于定义对象属性时可以配置以下参数:

  1. value(可选)
    • 这是属性的值。例如:
let obj = {};
Object.defineProperty(obj, 'name', {value: 'John'
});
console.log(obj.name); // 输出:John
  • 如果没有提供value参数,并且在对象中该属性不存在,那么这个属性的值将是undefined
  1. writable(可选)
    • 它是一个布尔值,用于确定属性的值是否可以被修改。默认值是false。例如:
let obj = {};
Object.defineProperty(obj, 'age', {value: 30,writable: true
});
obj.age = 31;
console.log(obj.age); // 输出:31
  • 如果writablefalse,尝试修改属性的值将会在严格模式下抛出错误,在非严格模式下修改操作会被忽略。
  1. enumerable(可选)
    • 这也是一个布尔值,用于决定属性是否可以被枚举,比如在for...in循环或者Object.keys()方法中是否会出现。默认值是false。例如:
let obj = {};
Object.defineProperty(obj, 'city', {value: 'New York',enumerable: true
});
for (let key in obj) {console.log(key); // 输出:city
}
  • 如果enumerablefalse,该属性在上述枚举操作中不会出现,但仍然可以通过直接访问属性名来获取其值。
  1. configurable(可选)
    • 同样是布尔值,它决定了这个属性是否可以被删除,以及是否可以重新配置属性的其他特性(除了valuewritable被设置为false后的情况)。默认值是false。例如:
let obj = {};
Object.defineProperty(obj, 'country', {value: 'USA',configurable: true
});
delete obj.country;
console.log(obj.country); // 输出:undefined
  • 如果configurablefalse,尝试删除属性或者重新配置其特性(如改变enumerable等)将会在严格模式下抛出错误,在非严格模式下操作会被忽略。

以下是一些Vue上层相关的底层面试题:

一、关于Vue实例

  1. Vue实例的生命周期钩子函数
    • 问题:请简述Vue实例的生命周期钩子函数有哪些,以及它们分别在什么时候被调用?
    • 答案:
      • beforeCreate:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。此时,datamethodscomputed等都还不可用。
      • created:在实例创建完成后被调用。此时实例已完成以下的配置:数据观测 (data observer)、属性和方法的运算、watch/event 事件回调。然而,挂载阶段还没开始,$el 不可用。
      • beforeMount:在挂载开始之前被调用。相关的 render 函数首次被调用。
      • mountedel 被新创建的 vm.$el 替换,并挂载到实例上去之后调用。一般在此进行DOM操作的初始化,例如获取元素的高度、宽度等操作,因为此时DOM已经渲染完成。
      • beforeUpdate:数据更新时调用,发生在虚拟DOM重新渲染和打补丁之前。此时DOM还没更新。
      • updated:由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。此时DOM已经更新。
      • beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。
      • destroyed:Vue实例销毁后调用。此时,Vue实例的所有指令都被解绑,所有的事件监听器被移除,子实例也被销毁。
  2. Vue实例的数据代理原理
    • 问题:请解释Vue是如何实现数据代理的?
    • 答案:
      • Vue通过Object.defineProperty()方法来实现数据代理。在Vue实例创建时,它会遍历data选项中的属性。
      • 对于每个属性,它会在Vue实例上定义一个同名的属性(如this.foo对应data中的foo属性)。
      • 这个同名属性的getset访问器函数被定义为读取和修改data中对应属性的值。当读取this.foo时,实际上是调用datafoo属性的get访问器;当修改this.foo时,是调用datafoo属性的set访问器。

二、关于Vue组件

  1. 组件通信方式
    • 问题:Vue组件有哪些通信方式?请举例说明。
    • 答案:
      • 父子组件通信
        • 父传子(props):父组件通过props向子组件传递数据。例如,父组件有一个message属性,在子组件中通过props: ['message']接收,然后在子组件的模板中可以使用{{message}}显示。
        • **子传父( e m i t ) ∗ ∗ :子组件通过 ‘ emit)**:子组件通过` emit:子组件通过emit触发事件向父组件传递数据。例如,子组件中有一个按钮,点击按钮时this.$emit(‘child - event’, data),父组件通过@child - event="parentMethod"监听这个事件,并在parentMethod`方法中接收子组件传递的数据。
      • 非父子组件通信(兄弟组件或跨多层级组件通信)
        • 中央事件总线(Event Bus):创建一个Vue实例作为事件总线。例如,var bus = new Vue()。一个组件可以通过bus.$emit('event - name', data)发送事件,其他组件通过bus.$on('event - name', callback)接收事件和数据。
        • Vuex:对于大型项目中复杂的状态管理和组件通信,使用Vuex。它有state(存储状态)、mutations(修改状态的方法)、actions(异步操作)和getters(获取状态的派生数据)。组件可以通过this.$store.state访问状态,通过this.$store.commit('mutation - name', data)提交修改状态的操作等。
  2. 组件的插槽(Slots)
    • 问题:请解释Vue组件中的插槽有哪些类型,以及它们的作用?
    • 答案:
      • 默认插槽(单个插槽)
        • 当在父组件中使用子组件时,如果在子组件标签内放置内容,这些内容会被渲染到子组件中的<slot>标签所在位置。例如,子组件ChildComponent中有一个<slot></slot>,父组件<ChildComponent>这是父组件传递的内容</ChildComponent>,“这是父组件传递的内容”就会被渲染到子组件的<slot>处。
      • 具名插槽
        • 当子组件有多个不同位置需要父组件填充内容时,可以使用具名插槽。在子组件中定义<slot name="header"></slot><slot name="footer"></slot>等。父组件使用<template v - slot:header><template v - slot:footer>来分别向对应的具名插槽传递内容。
      • 作用域插槽
        • 作用域插槽用于让父组件能够访问子组件中的数据。子组件在<slot>标签上绑定数据,如<slot :data="childData"></slot>。父组件通过<template v - slot="slotProps">slotProps是自定义的变量名)来接收子组件传递的数据,并在父组件中可以根据这些数据进行渲染,如{{slotProps.childData}}

三、关于Vue的渲染机制(除了Diff算法相关)

  1. 模板编译过程
    • 问题:简述Vue模板的编译过程。
    • 答案:
      • 解析(parse):将模板字符串解析成抽象语法树(AST)。这个过程会把模板中的HTML标签、指令、插值表达式等解析成JavaScript对象的形式。例如,模板<div>{{message}}</div>会被解析成一个包含tag: 'div'text: nullchildren: [ { type: 2, expression:'message', text: '{{message}}' } ]等属性的AST对象。
      • 优化(optimize):对解析后的AST进行优化,标记静态节点。静态节点是指在组件的生命周期内不会改变的节点,标记静态节点可以在后续的虚拟DOM更新过程中跳过这些节点的比较,提高性能。
      • 生成(generate):将优化后的AST转换成渲染函数(render函数)。渲染函数返回虚拟DOM(VNode),例如with(this){return _c('div',[_v(_s(message))])},其中_c_v_s等是Vue内部的渲染函数助手,用于创建VNode、创建文本节点、将数据转换为文本等操作。
  2. 渲染函数(Render Function)与模板的区别和联系
    • 问题:请说明Vue中渲染函数与模板的区别和联系,以及在什么情况下会选择使用渲染函数?
    • 答案:
      • 区别
        • 语法形式:模板是基于HTML的语法,通过指令(如v - ifv - for等)来添加逻辑;渲染函数是纯JavaScript函数,通过调用Vue内部的渲染函数助手来创建虚拟DOM。
        • 灵活性:渲染函数比模板更灵活。模板有一定的语法限制,而渲染函数可以实现更复杂的逻辑和渲染效果。例如,在模板中很难实现根据不同条件动态生成不同的HTML结构,但在渲染函数中可以通过JavaScript的条件判断来实现。
      • 联系
        • 模板最终会被编译成渲染函数。无论是使用模板还是直接编写渲染函数,目的都是生成虚拟DOM来渲染页面。
      • 选择使用渲染函数的情况
        • 当需要实现高度定制化的组件,模板的语法无法满足需求时,例如需要根据复杂的业务逻辑动态生成DOM结构。
        • 当需要对组件的渲染性能进行极致优化时,因为渲染函数可以更精确地控制虚拟DOM的生成和更新,通过优化渲染函数可以减少不必要的DOM操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/62711.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java对接AI大模型

随着AI大模型技术的升起,人们越来越感觉到生活上的便捷以及人机对话照进现实.什么是大模型呢? 大模型&#xff08;Large Model&#xff09;&#xff0c;通常是指参数量非常庞大的深度学习模型&#xff0c;特别是在自然语言处理&#xff08;NLP&#xff09;、计算机视觉&#…

Java开发网络安全常见问题

1、敏感信息明文传输 用户敏感信息如手机号、银行卡号、验证码等涉及个人隐私的敏感信息不通过任何加密直接明文传输。 如下图中小红书APP 的手机短信验证码登录接口&#xff0c;此处没有对用户手机号和验证码等信息进行加密传输&#xff0c;可以很简单的截取并开展一些合法的…

【CSS in Depth 2 精译_063】10.2 深入理解 CSS 容器查询中的容器

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 【第十章 CSS 容器查询】 ✔️ 10.1 容器查询的一个简单示例 10.1.1 容器尺寸查询的用法 10.2 深入理解容器 ✔️ 10.2.1 容器的类型 ✔️10.2.2 容器的名称 ✔️10.2.3 容器与模块化 CSS ✔️ 10.3…

基于Springboot开发的时光兼职网

一、功能介绍 时光兼职网包含管理员、用户、商家三个角色以及前后台系统。 前台系统功能 首页、兼职信息推荐、查看更多等 职位申请、申请日期、上传简历、点击下载简历、留言反馈等 个人中心、上传图片、更新信息等 后台系统功能 用户登录&#xff1a; 个人中心、修改密码…

计算机的错误计算(一百七十一)

摘要 探讨 MATLAB 中秦九韶&#xff08;Horner&#xff09;多项式的错误计算。 例1. 用秦九韶&#xff08;Horner&#xff09;算法计算&#xff08;一百零七&#xff09;例1中多项式 直接贴图吧&#xff1a; 这样&#xff0c;MATLAB 给出的仍然是错误结果&#xff0c;因为准…

代码美学3:RGB转化+MATLAB制作渐变色

RGB颜色转化器&#xff08;转换成matlab可以读取的形式&#xff09; n input(请输入 n&#xff1a;); color_matrix cell(1, n); for i 1:nR input(请输入 R 值&#xff1a;);G input(请输入 G 值&#xff1a;);B input(请输入 B 值&#xff1a;);color_matrix{i} [R/2…

kafka数据在服务端时怎么写入的

学习背景 接着上篇&#xff0c;我们来聊聊kafka数据在服务端怎么写入的 服务端写入 在介绍服务端的写流程之前&#xff0c;我们先要理解服务端的几个角色之间的关系。 假设我们有一个由3个broker组成的kafka集群&#xff0c;我们在这个集群上创建一个topic叫做shitu-topic&…

rabbitmq原理及命令

目录 一、RabbitMQ原理1、交换机&#xff08;Exchange&#xff09;fanoutdirecttopicheaders&#xff08;很少用到&#xff09; 2、队列Queue3、Virtual Hosts4、基础对象 二、RabbitMQ的一些基本操作:1、用户管理2、用户角色3、vhost4、开启web管理接口5、批量删除队列 一、Ra…

Kali Linux怎么开python虚拟环境

相信很多朋友再学习的过程中都会遇到一些pip失效&#xff0c;或者报错的时候&#xff0c;他们要求我们要使用虚拟环境&#xff0c;但是不知道怎么搭建&#xff0c;下面这篇文章就来告诉你如何搭建虚拟环境&#xff0c;这个方法在所有Linux的服务器都通用&#xff0c;就两行命令…

【博主推荐】C# Winform 拼图小游戏源码详解(附源码)

文章目录 前言摘要1.设计来源拼图小游戏讲解1.1 拼图主界面设计1.2 一般难度拼图效果1.3 普通难度拼图效果1.4 困难难度拼图效果1.5 地域难度拼图效果1.6 内置五种拼图效果 2.效果和源码2.1 动态效果2.2 源代码 源码下载结束语 前言 在数字浪潮汹涌澎湃的时代&#xff0c;程序开…

React Native学习笔记(三)

一 组件简介 1.1 简介 RN中的核心组件&#xff0c;是对原生组件的封装 原生组件&#xff1a;Android或ios内的组件核心组件&#xff1a;RN中常用的&#xff0c;来自react-native的组件 原生组件 在 Android 开发中是使用 Kotlin 或 Java 来编写视图&#xff1b;在 iOS 开发…

视觉语言动作模型VLA的持续升级:从π0之参考基线Octo到OpenVLA、TinyVLA、DeeR-VLA、3D-VLA

第一部分 VLA模型π0之参考基线Octo 1.1 Octo的提出背景与其整体架构 1.1.1 Octo的提出背景与相关工作 许多研究使用从机器人收集的大量轨迹数据集来训练策略 从早期使用自主数据收集来扩展策略训练的工作[71,48,41,19-Robonet,27,30]到最近探索将现代基于transformer的策略…

C与指针。

目录 1_指针理解 1.1变量的值 1.2变量的地址 1.3指针 1.4取变量的地址 2_分析指针 2.1分析指针变量的要素 2.2根据需求定义指针变量 3_指针的使用 3.1指针对变量的读操作 3.2指针对变量的写操作 4_指针占用空间的大小与位移 4.1指针占用空间的大小 4.2指针的位移…

单片机学习笔记 15. 串口通信(理论)

更多单片机学习笔记&#xff1a;单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘单片机学习笔记 8…

树莓派5+文心一言 -> 智能音箱

一、简介 效果&#xff1a;运行起来后&#xff0c;可以连续对话 硬件&#xff1a;树莓派5、麦克风、音箱&#xff0c;成本500-1000 软件&#xff1a;snowboy作为唤醒词、百度语音作为语音识别、brain作为指令匹配、百度文心一言作为对话模块、微软的edge-tts语音合成... 二…

SAP SD学习笔记17 - 投诉处理3 - Credit/Debit Memo依赖,Credit/Debit Memo

上一章讲了 请求书&#xff08;发票&#xff09;的取消。 SAP SD学习笔记16 - 请求书的取消 - VF11-CSDN博客 再往上几章&#xff0c;讲了下图里面的返品传票&#xff1a; SAP SD学习笔记14 - 投诉处理1 - 返品处理&#xff08;退货处理&#xff09;的流程以及系统实操&#…

Linux服务器使用JupyterLab

一、JupyterLab的配置 1. conda配置 自行搜索conda安装与配置。 2. 环境创建 &#xff08;1&#xff09;创建环境 conda create -n jupyter python3.10&#xff08;2&#xff09;激活环境 conda activate jupyter&#xff08;3&#xff09;安装jupyter包 pip install -i…

Flutter:页面滚动

1、单一页面&#xff0c;没有列表没分页的&#xff0c;推荐使用&#xff1a;SingleChildScrollView() return Scaffold(backgroundColor: Color(0xffF6F6F6),body: SingleChildScrollView(child: _buildView()) );2、列表没分页&#xff0c;如购物车页&#xff0c;每个item之间…

使用GitZip for github插件下载git仓库中的单个文件

背景&#xff1a;git仓库不知道抽什么疯&#xff0c;下载不了单个文件&#xff0c;点击下载没有反应&#xff0c;遂找寻其他方法&#xff0c;在这里简单记录下。 使用GitZip for github插件下载仓库中的单个文件 1、首先在浏览器安装插件&#xff0c;并确保为打开状态。 2、然…

Unet改进57:在不同位置添加SFHF

本文内容:在不同位置添加CBAM注意力机制 论文简介 由于恶劣的大气条件或独特的降解机制,自然图像会遭受各种退化现象。这种多样性使得为各种恢复任务设计一个通用框架具有挑战性。现有的图像恢复方法没有探索不同退化现象之间的共性,而是侧重于在有限的恢复先验下对网络结构…