前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >京东前端二面常见vue面试题及答案_2023-02-28

京东前端二面常见vue面试题及答案_2023-02-28

原创
作者头像
yyds2026
发布于 2023-02-28 03:00:28
发布于 2023-02-28 03:00:28
57600
代码可运行
举报
文章被收录于专栏:前端开发面经前端开发面经
运行总次数:0
代码可运行

虚拟 DOM 的优缺点?

优点:

  • 保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;
  • 无需手动操作 DOM: 我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;
  • 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。

缺点:

  • 无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。

Vue中key的作用

vue 中 key 值的作用可以分为两种情况来考虑:

  • 第一种情况是 v-if 中使用 key。由于 Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。因此当使用 v-if 来实现元素切换的时候,如果切换前后含有相同类型的元素,那么这个元素就会被复用。如果是相同的 input 元素,那么切换前后用户的输入不会被清除掉,这样是不符合需求的。因此可以通过使用 key 来唯一的标识一个元素,这个情况下,使用 key 的元素不会被复用。这个时候 key 的作用是用来标识一个独立的元素。
  • 第二种情况是 v-for 中使用 key。用 v-for 更新已渲染过的元素列表时,它默认使用“就地复用”的策略。如果数据项的顺序发生了改变,Vue 不会移动 DOM 元素来匹配数据项的顺序,而是简单复用此处的每个元素。因此通过为每个列表项提供一个 key 值,来以便 Vue 跟踪元素的身份,从而高效的实现复用。这个时候 key 的作用是为了高效的更新渲染虚拟 DOM。

key 是为 Vue 中 vnode 的唯一标记,通过这个 key,diff 操作可以更准确、更快速

  • 更准确:因为带 key 就不是就地复用了,在 sameNode 函数a.key === b.key对比中可以避免就地复用的情况。所以会更加准确。
  • 更快速:利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快

Vue组件data为什么必须是个函数?

  • 根实例对象data可以是对象也可以是函数 (根实例是单例),不会产生数据污染情况
  • 组件实例对象data必须为函数 一个组件被复用多次的话,也就会创建多个实例。本质上,这些实例用的都是同一个构造函数。如果data是对象的话,对象属于引用类型,会影响到所有的实例。所以为了保证组件不同的实例之间data不冲突,data必须是一个函数,

简版理解

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 1.组件的渲染流程 调用Vue.component -> Vue.extend -> 子类 -> new 子类
// Vue.extend 根据用户定义产生一个新的类
function Vue() {}
function Sub() { // 会将data存起来
    this.data = this.constructor.options.data();
}
Vue.extend = function(options) {
    Sub.options = options; // 静态属性
    return Sub;
}
let Child = Vue.extend({
    data:()=>( { name: 'zf' })
});

// 两个组件就是两个实例, 希望数据互不感染
let child1 = new Child();
let child2 = new Child();

console.log(child1.data.name);
child1.data.name = 'poetry';
console.log(child2.data.name);

// 根不需要 任何的合并操作   根才有vm属性 所以他可以是函数和对象  但是组件mixin他们都没有vm 所以我就可以判断 当前data是不是个函数

相关源码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 源码位置 src/core/global-api/extend.js
export function initExtend (Vue: GlobalAPI) {
  Vue.extend = function (extendOptions: Object): Function {
    extendOptions = extendOptions || {}
    const Super = this
    const SuperId = Super.cid
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    if (cachedCtors[SuperId]) {
      return cachedCtors[SuperId]
    }

    const name = extendOptions.name || Super.options.name
    if (process.env.NODE_ENV !== 'production' && name) {
      validateComponentName(name)
    }

    const Sub = function VueComponent (options) {
      this._init(options)
    }
    // 子类继承大Vue父类的原型
    Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
    Sub.cid = cid++
    Sub.options = mergeOptions(
      Super.options,
      extendOptions
    )
    Sub['super'] = Super

    // For props and computed properties, we define the proxy getters on
    // the Vue instances at extension time, on the extended prototype. This
    // avoids Object.defineProperty calls for each instance created.
    if (Sub.options.props) {
      initProps(Sub)
    }
    if (Sub.options.computed) {
      initComputed(Sub)
    }

    // allow further extension/mixin/plugin usage
    Sub.extend = Super.extend
    Sub.mixin = Super.mixin
    Sub.use = Super.use

    // create asset registers, so extended classes
    // can have their private assets too.
    ASSET_TYPES.forEach(function (type) {
      Sub[type] = Super[type]
    })
    // enable recursive self-lookup
    if (name) { 
      Sub.options.components[name] = Sub // 记录自己 在组件中递归自己  -> jsx
    }

    // keep a reference to the super options at extension time.
    // later at instantiation we can check if Super's options have
    // been updated.
    Sub.superOptions = Super.options
    Sub.extendOptions = extendOptions
    Sub.sealedOptions = extend({}, Sub.options)

    // cache constructor
    cachedCtors[SuperId] = Sub
    return Sub
  }
}

Vue 的生命周期方法有哪些 一般在哪一步发请求

beforeCreate 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。在当前阶段 data、methods、computed 以及 watch 上的数据和方法都不能被访问

created 实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。这里没有$el,如果非要想与 Dom 进行交互,可以通过 vm.$nextTick 来访问 Dom

beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。

mounted 在挂载完成后发生,在当前阶段,真实的 Dom 挂载完毕,数据完成双向绑定,可以访问到 Dom 节点

beforeUpdate 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁(patch)之前。可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程

updated 发生在更新完成之后,当前阶段组件 Dom 已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新,该钩子在服务器端渲染期间不被调用。

beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。我们可以在这时进行善后收尾工作,比如清除计时器。

destroyed Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。

activated keep-alive 专属,组件被激活时调用

deactivated keep-alive 专属,组件被销毁时调用

异步请求在哪一步发起?

可以在钩子函数 created、beforeMount、mounted 中进行异步请求,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。

如果异步请求不需要依赖 Dom 推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:

  • 能更快获取到服务端数据,减少页面 loading 时间;
  • ssr 不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性;

v-show 与 v-if 有什么区别?

v-if真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 “display” 属性进行切换。

所以,v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。

Computed 和 Watch 的区别

对于Computed:

  • 它支持缓存,只有依赖的数据发生了变化,才会重新计算
  • 不支持异步,当Computed中有异步操作时,无法监听数据的变化
  • computed的值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data声明过,或者父组件传递过来的props中的数据进行计算的。
  • 如果一个属性是由其他属性计算而来的,这个属性依赖其他的属性,一般会使用computed
  • 如果computed属性的属性值是函数,那么默认使用get方法,函数的返回值就是属性的属性值;在computed中,属性有一个get方法和一个set方法,当数据发生变化时,会调用set方法。

对于Watch:

  • 它不支持缓存,数据变化时,它就会触发相应的操作
  • 支持异步监听
  • 监听的函数接收两个参数,第一个参数是最新的值,第二个是变化之前的值
  • 当一个属性发生变化时,就需要执行相应的操作
  • 监听数据必须是data中声明的或者父组件传递过来的props中的数据,当发生变化时,会触发其他操作,函数有两个的参数:
    • immediate:组件加载立即触发回调函数
    • deep:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。需要注意的是,deep无法监听到数组和对象内部的变化。

当想要执行异步或者昂贵的操作以响应不断的变化时,就需要使用watch。

总结:

  • computed 计算属性 : 依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。
  • watch 侦听器 : 更多的是观察的作用,无缓存性,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作。

运用场景:

  • 当需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时都要重新计算。
  • 当需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许执行异步操作 ( 访问一个 API ),限制执行该操作的频率,并在得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

一般在哪个生命周期请求异步数据

我们可以在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。

推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:

  • 能更快获取到服务端数据,减少页面加载时间,用户体验更好;
  • SSR不支持 beforeMount 、mounted 钩子函数,放在 created 中有助于一致性。

diff算法

时间复杂度: 个树的完全diff 算法是一个时间复杂度为O(n*3) ,vue进行优化转化成O(n)

理解:

  • 最小量更新,key 很重要。这个可以是这个节点的唯一标识,告诉diff 算法,在更改前后它们是同一个DOM节点
    • 扩展v-for 为什么要有key ,没有key 会暴力复用,举例子的话随便说一个比如移动节点或者增加节点(修改DOM),加key 只会移动减少操作DOM。
  • 只有是同一个虚拟节点才会进行精细化比较,否则就是暴力删除旧的,插入新的。
  • 只进行同层比较,不会进行跨层比较。

diff算法的优化策略:四种命中查找,四个指针

  1. 旧前与新前(先比开头,后插入和删除节点的这种情况)
  2. 旧后与新后(比结尾,前插入或删除的情况)
  3. 旧前与新后(头与尾比,此种发生了,涉及移动节点,那么新前指向的节点,移动到旧后之后)
  4. 旧后与新前(尾与头比,此种发生了,涉及移动节点,那么新前指向的节点,移动到旧前之前)

过滤器的作用,如何实现一个过滤器

根据过滤器的名称,过滤器是用来过滤数据的,在Vue中使用filters来过滤数据,filters不会修改数据,而是过滤数据,改变用户看到的输出(计算属性 computed ,方法 methods 都是通过修改数据来处理数据格式的输出显示)。

使用场景:

  • 需要格式化数据的情况,比如需要处理时间、价格等数据格式的输出 / 显示。
  • 比如后端返回一个 年月日的日期字符串,前端需要展示为 多少天前 的数据格式,此时就可以用fliters过滤器来处理数据。

过滤器是一个函数,它会把表达式中的值始终当作函数的第一个参数。过滤器用在插值表达式 {{ }}v-bind 表达式 中,然后放在操作符“ | ”后面进行指示。

例如,在显示金额,给商品价格添加单位:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<li>商品价格:{{item.price | filterPrice}}</li>

 filters: {
    filterPrice (price) {
      return price ? ('¥' + price) : '--'
    }
  }

v-model 的原理?

我们在 vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

  • text 和 textarea 元素使用 value 属性和 input 事件;
  • checkbox 和 radio 使用 checked 属性和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

以 input 表单元素为例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<input v-model='something'>

相当于

<input v-bind:value="something" v-on:input="something = $event.target.value">

如果在自定义组件中,v-model 默认会利用名为 value 的 prop 和名为 input 的事件,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
父组件:
<ModelChild v-model="message"></ModelChild>

子组件:
<div>{{value}}</div>

props:{
    value: String
},
methods: {
  test1(){
     this.$emit('input', '小红')
  },
},

双向数据绑定的原理

Vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。主要分为以下几个步骤:

  1. 需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
  2. compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
  3. Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是: ①在自身实例化时往属性订阅器(dep)里面添加自己 ②自身必须有一个update()方法 ③待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
  4. MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

对SSR的理解

SSR也就是服务端渲染,也就是将Vue在客户端把标签渲染成HTML的工作放在服务端完成,然后再把html直接返回给客户端

SSR的优势:

  • 更好的SEO
  • 首屏加载速度更快

SSR的缺点:

  • 开发条件会受到限制,服务器端渲染只支持beforeCreate和created两个钩子;
  • 当需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于Node.js的运行环境;
  • 更多的服务端负载。

Vue 中 computed 和 watch 有什么区别?

计算属性 computed

代码语言:txt
AI代码解释
复制
 (1)**支持缓存**,只有依赖数据发生变化时,才会重新进行计算函数;
代码语言:txt
AI代码解释
复制
 (2)计算属性内**不支持异步操作**;
代码语言:txt
AI代码解释
复制
 (3)计算属性的函数中**都有一个 get**(默认具有,获取计算属性)**和 set**(手动添加,设置计算属性)方法;
代码语言:txt
AI代码解释
复制
 (4)计算属性是自动监听依赖值的变化,从而动态返回内容。

侦听属性 watch

代码语言:txt
AI代码解释
复制
 (1)**不支持缓存**,只要数据发生变化,就会执行侦听函数;
代码语言:txt
AI代码解释
复制
 (2)侦听属性内**支持异步操作**;
代码语言:txt
AI代码解释
复制
 (3)侦听属性的值**可以是一个对象,接收 handler 回调,deep,immediate 三个属性**;
代码语言:txt
AI代码解释
复制
 (3)监听是一个过程,在监听的值变化时,可以触发一个回调,并**做一些其他事情**。

Vue模版编译原理知道吗,能简单说一下吗?

简单说,Vue的编译过程就是将template转化为render函数的过程。会经历以下阶段:

  • 生成AST树
  • 优化
  • codegen

首先解析模版,生成AST语法树(一种用JavaScript对象的形式来描述整个模板)。 使用大量的正则表达式对模板进行解析,遇到标签、文本的时候都会执行对应的钩子进行相关处理。

Vue的数据是响应式的,但其实模板中并不是所有的数据都是响应式的。有一些数据首次渲染后就不会再变化,对应的DOM也不会变化。那么优化过程就是深度遍历AST树,按照相关条件对树节点进行标记。这些被标记的节点(静态节点)我们就可以跳过对它们的比对,对运行时的模板起到很大的优化作用。

编译的最后一步是将优化后的AST树转换为可执行的代码

怎么缓存当前的组件?缓存后怎么更新

缓存组件使用keep-alive组件,这是一个非常常见且有用的优化手段,vue3keep-alive有比较大的更新,能说的点比较多

思路

  • 缓存用keep-alive,它的作用与用法
  • 使用细节,例如缓存指定/排除、结合routertransition
  • 组件缓存后更新可以利用activated或者beforeRouteEnter
  • 原理阐述

回答范例

  1. 开发中缓存组件使用keep-alive组件,keep-alivevue内置组件,keep-alive包裹动态组件component时,会缓存不活动的组件实例,而不是销毁它们,这样在组件切换过程中将状态保留在内存中,防止重复渲染DOM
代码语言:html
AI代码解释
复制
<keep-alive>
  <component :is="view"></component>
</keep-alive>
  1. 结合属性includeexclude可以明确指定缓存哪些组件或排除缓存指定组件。vue3中结合vue-router时变化较大,之前是keep-alive包裹router-view,现在需要反过来用router-view包裹keep-alive
代码语言:html
AI代码解释
复制
<router-view v-slot="{ Component }">
  <keep-alive>
    <component :is="Component"></component>
  </keep-alive>
</router-view>
  1. 缓存后如果要获取数据,解决方案可以有以下两种
  2. beforeRouteEnter:在有vue-router的项目,每次进入路由的时候,都会执行beforeRouteEnter
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
beforeRouteEnter(to, from, next){
  next(vm=>{
    console.log(vm)
    // 每次进入路由执行
    vm.getData()  // 获取数据
  })
},
  • actived:在keep-alive缓存的组件被激活的时候,都会执行actived钩子
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
activated(){
    this.getData() // 获取数据
},
  1. keep-alive是一个通用组件,它内部定义了一个map,缓存创建过的组件实例,它返回的渲染函数内部会查找内嵌的component组件对应组件的vnode,如果该组件在map中存在就直接返回它。由于componentis属性是个响应式数据,因此只要它变化,keep-aliverender函数就会重新执行

双向绑定的原理是什么

我们都知道 Vue 是数据双向绑定的框架,双向绑定由三个重要部分构成

  • 数据层(Model):应用的数据及业务逻辑
  • 视图层(View):应用的展示效果,各类UI组件
  • 业务逻辑层(ViewModel):框架封装的核心,它负责将数据与视图关联起来

而上面的这个分层的架构方案,可以用一个专业术语进行称呼:MVVM这里的控制层的核心功能便是 “数据双向绑定” 。自然,我们只需弄懂它是什么,便可以进一步了解数据绑定的原理

理解ViewModel

它的主要职责就是:

  • 数据变化后更新视图
  • 视图变化后更新数据

当然,它还有两个主要部分组成

  • 监听器(Observer):对所有数据的属性进行监听
  • 解析器(Compiler):对每个元素节点的指令进行扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数

能说下 vue-router 中常用的 hash 和 history 路由模式实现原理吗?

(1)hash 模式的实现原理

早期的前端路由的实现就是基于 location.hash 来实现的。其实现原理很简单,location.hash 的值就是 URL 中 # 后面的内容。比如下面这个网站,它的 location.hash 的值为 '#search':

代码语言:txt
AI代码解释
复制
https://www.word.com#search

hash 路由模式的实现主要是基于下面几个特性:

  • URL 中 hash 值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash 部分不会被发送;

hash 值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash 的切换;

  • 可以通过 a 标签,并设置 href 属性,当用户点击这个标签后,URL 的 hash 值会发生改变;或者使用 JavaScript 来对 loaction.hash 进行赋值,改变 URL 的 hash 值;
  • 我们可以使用 hashchange 事件来监听 hash 值的变化,从而对页面进行跳转(渲染)。

(2)history 模式的实现原理

HTML5 提供了 History API 来实现 URL 的变化。其中做最主要的 API 有以下两个:history.pushState() 和 history.repalceState()。这两个 API 可以在不进行刷新的情况下,操作浏览器的历史纪录。唯一不同的是,前者是新增一个历史记录,后者是直接替换当前的历史记录,如下所示:

代码语言:txt
AI代码解释
复制
window.history.pushState(null, null, path);
window.history.replaceState(null, null, path);

history 路由模式的实现主要基于存在下面几个特性:

  • pushState 和 repalceState 两个 API 来操作实现 URL 的变化 ;
  • 我们可以使用 popstate 事件来监听 url 的变化,从而对页面进行跳转(渲染);
  • history.pushState() 或 history.replaceState() 不会触发 popstate 事件,这时我们需要手动触发页面跳转(渲染)。

函数式组件优势和原理

函数组件的特点

  1. 函数式组件需要在声明组件是指定 functional:true
  2. 不需要实例化,所以没有this,this通过render函数的第二个参数context来代替
  3. 没有生命周期钩子函数,不能使用计算属性,watch
  4. 不能通过$emit 对外暴露事件,调用事件只能通过context.listeners.click的方式调用外部传入的事件
  5. 因为函数式组件是没有实例化的,所以在外部通过ref去引用组件时,实际引用的是HTMLElement
  6. 函数式组件的props可以不用显示声明,所以没有在props里面声明的属性都会被自动隐式解析为prop,而普通组件所有未声明的属性都解析到$attrs里面,并自动挂载到组件根元素上面(可以通过inheritAttrs属性禁止)

优点

  1. 由于函数式组件不需要实例化,无状态,没有生命周期,所以渲染性能要好于普通组件
  2. 函数式组件结构比较简单,代码结构更清晰

使用场景:

  • 一个简单的展示组件,作为容器组件使用 比如 router-view 就是一个函数式组件
  • “高阶组件”——用于接收一个组件作为参数,返回一个被包装过的组件

例子

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Vue.component('functional',{ // 构造函数产生虚拟节点的
    functional:true, // 函数式组件 // data={attrs:{}}
    render(h){
        return h('div','test')
    }
})
const vm = new Vue({
    el: '#app'
})

源码相关

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// functional component
if (isTrue(Ctor.options.functional)) { // 带有functional的属性的就是函数式组件
  return createFunctionalComponent(Ctor, propsData, data, context, children)
}

// extract listeners, since these needs to be treated as
// child component listeners instead of DOM listeners
const listeners = data.on // 处理事件
// replace with listeners with .native modifier
// so it gets processed during parent component patch.
data.on = data.nativeOn // 处理原生事件

// install component management hooks onto the placeholder node
installComponentHooks(data) // 安装组件相关钩子 (函数式组件没有调用此方法,从而性能高于普通组件)

Vue 为什么要用 vm.$set() 解决对象新增属性不能响应的问题 ?你能说说如下代码的实现原理么?

1)Vue为什么要用vm.$set() 解决对象新增属性不能响应的问题

  1. Vue使用了Object.defineProperty实现双向数据绑定
  2. 在初始化实例时对属性执行 getter/setter 转化
  3. 属性必须在data对象上存在才能让Vue将它转换为响应式的(这也就造成了Vue无法检测到对象属性的添加或删除)

所以Vue提供了Vue.set (object, propertyName, value) / vm.$set (object, propertyName, value)

2)接下来我们看看框架本身是如何实现的呢?

Vue 源码位置:vue/src/core/instance/index.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export function set (target: Array<any> | Object, key: any, val: any): any {
  // target 为数组  
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    // 修改数组的长度, 避免索引>数组长度导致splcie()执行有误
    target.length = Math.max(target.length, key)
    // 利用数组的splice变异方法触发响应式  
    target.splice(key, 1, val)
    return val
  }
  // key 已经存在,直接修改属性值  
  if (key in target && !(key in Object.prototype)) {
    target[key] = val
    return val
  }
  const ob = (target: any).__ob__
  // target 本身就不是响应式数据, 直接赋值
  if (!ob) {
    target[key] = val
    return val
  }
  // 对属性进行响应式处理
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

我们阅读以上源码可知,vm.$set 的实现原理是:

  1. 如果目标是数组,直接使用数组的 splice 方法触发相应式;
  2. 如果目标是对象,会先判读属性是否存在、对象是否是响应式,
  3. 最终如果要对属性进行响应式处理,则是通过调用 defineReactive 方法进行响应式处理

defineReactive 方法就是 Vue 在初始化对象时,给对象属性采用 Object.defineProperty 动态添加 getter 和 setter 的功能所调用的方法

delete和Vue.delete删除数组的区别

  • delete 只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。
  • Vue.delete 直接删除了数组 改变了数组的键值。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
单一癌种综合分析也能发8分+SCI
大家好!今天给大家介绍一篇2022年6月发表在Journal of Translational Medicine(IF:8.440)上的一篇文章。本研究作者全面分析了胶质瘤患者的小胶质细胞的作用并基于相应亚通路构建预后模型。
百味科研芝士
2022/12/12
3960
单一癌种综合分析也能发8分+SCI
4+分的Aging现在得补这么多湿实验了!
今天和大家分享的是2020年发表在 Aging(IF:4.831) 上的一篇文章,“Elevated lymphocyte specific protein 1 expression is involved in the regulation of leukocyte migration and immunosuppressive microenvironment in glioblastoma ”。作者使用CGGA和TCGA的数据,分析GBM中白细胞迁移相关基因的表达,发现LSP1不仅表达升高,而且还作为GBM的独立预测因子,在临床肿瘤样本中进一步验证了该结果。此外,通过KM生存分析得:LSP1的表达与GBM肿瘤对放疗和化疗的反应密切相关;并通过功能基因富集分析和MCP-counter分析得:LSP1有助于GBM的肿瘤免疫抑制微环境。
科研菌
2020/08/07
8530
4+分的Aging现在得补这么多湿实验了!
缺氧结合免疫微环境如何打造4分+纯生信文章?
大家好!今天跟大家分享的是2020年5月发表在Frontiers in Oncology(IF = 4.848)上的文章。文章利用TCGA及CGGA数据库中胶质瘤病人表达谱数据进行低氧相关基因表达分析,基于CGGA数据集通过Cox回归分析建立模型,通过TCGA数据进行模型验证,先后利用生存曲线分析,ROC曲线分析,GSEA分析和相关性分析等方法,阐述了低氧风险模型与神经胶质瘤的预后、临床指标和免疫微环境的关系。
百味科研芝士
2020/07/09
1.7K0
缺氧结合免疫微环境如何打造4分+纯生信文章?
想要创新,预后模型还能从哪儿入手?这篇4分+文章给你答案
大家好!今天跟大家分享的文献是2020年12月发表在JOURNAL OF CELLULAR AND MOLECULAR MEDICINE(IF=4.486)杂志上的一篇文章。本研究分析TCGA,CGGA和GEO数据集和ER应激相关基因进行分析,构建ER应激相关风险特征,研究神经胶质瘤患者的免疫特征和预测患者预后。
百味科研芝士
2021/04/21
7100
想要创新,预后模型还能从哪儿入手?这篇4分+文章给你答案
7+分析思路!巨噬细胞的分子特征与肿瘤免疫微环境联合分析!
神经胶质瘤是中枢神经系统中最常见的原发性肿瘤类型之一。先前的研究发现,巨噬细胞积极参与肿瘤的生长。
作图丫
2022/03/29
5610
7+分析思路!巨噬细胞的分子特征与肿瘤免疫微环境联合分析!
免疫相关基因预后模型构建,这个套路不香吗?
大家好,今天向大家分享的是2020年4月发表在Frontiers in Genetics (IF=3.517) 杂志上的一篇文献《Novel Immune-Related Gene Signature for Risk Stratification and Prognosis of Survival in Lower-Grade Glioma》。文章基于TCGA数据库和CGGA数据库中的脑胶质瘤相关数据,利用单因素、多因素Cox回归分析及Lasso算法构建了六个免疫相关基因签名(gene signature,或者叫标记基因),并建立了预后诺模图,可有效地进行风险分层和预测原发性LGG的整体生存。
用户6317549
2020/07/22
3.8K0
免疫相关基因预后模型构建,这个套路不香吗?
一文带你学会如何通过多维度的分析来论证同一个假设
大家好,今天和大家分享的是一月份发表在Cancer cell international (IF:4.175)杂志上的一篇文章,“Multi-dimensional omics characterization in glioblastoma identifies the purity-associated pattern and prognostic gene signatures”,作者通过对于TCGA,CGGA(中国人脑胶质瘤基因组图谱)和GEO数据库中胶质母细胞瘤的患者测序信息进行分析,研究了肿瘤纯度在GBM预后,基因组以及转录组改变和肿瘤免疫微环境中的作用,并构造了一个肿瘤纯度相关的五基因signature。
科研菌
2020/08/20
1K0
一文带你学会如何通过多维度的分析来论证同一个假设
依然是热点!铜死亡基因构建预后模型发表6分+
今天小编继续为大家带来铜死亡系列的热点文章,本文依然是纯生信,没有补充实验,发表在6分+的计算机/数学类期刊Computers in Biology and Medicine上,所以也提示大家也不要再卷肿瘤期刊啦,可以尝试其他生信/计算机类期刊。
作图丫
2022/12/04
5060
依然是热点!铜死亡基因构建预后模型发表6分+
生信分析需要多维度的验证:多数据集和湿实验
Development and validation of a nomogram with an autophagy-related gene signature for predicting survival in patients with glioblastoma
科研菌
2020/07/28
2.8K0
利用转录组数据构建预后模型的8分+发文技巧
大家好!今天给大家介绍一篇2022年4月发表在eBioMedicine(IF:8.143)上的一篇文章。作者基于LGG患者的转录组数据构建可以准确预测患者预后的模型-APOLLO。
生信交流平台
2022/09/21
1K0
利用转录组数据构建预后模型的8分+发文技巧
Nature | 代码值得学习!发现RNA剪接异常产生的新一类“公共新抗原”,公共数据挖掘
◉ TCGA RNA-seq 数据在胶质母细胞瘤 (GBM,n = 167 个样本)、低级别胶质瘤 (LGG,n = 516)、肺腺癌 (LUAD,n = 517)、肺鳞状细胞癌 (LUSC,n = 501)、间皮瘤 (MESO,n = 516)、肝细胞癌 (LIHC,n = 371)、胃腺癌 (STAD,n = 415)、皮肤黑色素瘤 (SKCM,n = 470)、肾乳头状细胞癌 (KIRP,n = 290)、肾嫌色细胞癌 (KICH,n = 66)、结肠腺癌 (COAD,n = 458) 和前列腺腺癌 (PRAD,n = 497) 中进行了分析。◉ 选取肿瘤纯度 ≥60% 的样本(实心颜色)进行分析,由于缺乏纯度数据,排除了 MESO 和 STAD 样本。◉ 对患者间的 NJ 频率 (PSR) 进行了分析,其中公共 NJ 被定义为 PSR ≥10%(红线)。◉ 按肿瘤类型统计了每例样本中检测到的公共 NJ 的总数(d)和 log2[读段频率](e)(COAD,n = 265;GBM,n = 391;KICH,n = 773;KIRP,n = 247;LGG,n = 327;LIHC,n = 173;LUAD,n = 175;LUSC,n = 555;MESO,n = 277;PRAD,n = 245;SKCM,n = 353;STAD,n = 1,433)。◉ 根据剪接类型对公共 NJ 进行分类:3′ 或 5′ 剪接位点的外显子丢失 (A3 或 A5 丢失 (A3−; A5−))、3′ 或 5′ 剪接位点的内含子获得 (A3 或 A5 获得 (A3+; A5+))、外显子跳跃 (ES)、外显子内的连接、内含子内的连接和其他类型(f),以及框移 (FS) 状态(g);IF 表示同框。◉ 所有泛癌症范围的 NJ 在所有研究的 TCGA 肿瘤类型中的表达情况(log2[每百万计数 (CPM)])。◉ 更多的统计细节见补充表 3。图 a 使用 BioRender 创建(致谢:D.W.K.,https://BioRender.com/k09l557;2024 年)。
生信菜鸟团
2025/03/21
2970
Nature | 代码值得学习!发现RNA剪接异常产生的新一类“公共新抗原”,公共数据挖掘
SCIENCE | 人类胶质母细胞瘤中不同类型的髓源抑制性细胞群体
2025年4月4日约翰霍普金斯大学等团队联合攻关,Science 以封面论文形式发表了题为:Distinct Myeloid-Derived Suppressor Cell Populations in Human Glioblastoma 的研究论文。首次应用单细胞RNA测序技术,结合空间转录组学,系统解析了人类胶质母细胞瘤(GBM)中髓源抑制性细胞(MDSC)的多阶段空间演化图谱,揭示了不同MDSC亚群在IDH野生型胶质母细胞瘤中的特异性分布和功能演化。研究突破了传统肿瘤免疫逃逸模型的局限,创新性地提出了“肿瘤微环境免疫交互”理论框架,首次揭示了肿瘤相关成纤维细胞(CAF)与侵袭性肿瘤细胞在胶质母细胞瘤发展中的关键相互作用机制。这一关键免疫生态位的发现为胶质母细胞瘤的免疫抑制机制提供了新的理解,并可能为早期诊断和治疗策略的开发提供理论支持,对提高胶质母细胞瘤的临床治疗效果具有重要意义。
用户11646841
2025/05/08
1090
SCIENCE | 人类胶质母细胞瘤中不同类型的髓源抑制性细胞群体
8+!胶质母细胞瘤中铁死亡相关模型构建~
胶质瘤是中枢神经系统的侵袭性肿瘤,胶质母细胞瘤是最恶性的类型。铁死亡是一种程序性细胞死亡,可以调节肿瘤对治疗的抵抗力和肿瘤微环境的成分。
作图丫
2022/12/14
4590
8+!胶质母细胞瘤中铁死亡相关模型构建~
Radiology:人工智能在神经肿瘤学中的新兴应用
随着计算机算法呈指数式增长,人工智能(AI)方法有望提高医学诊断和治疗方法的精确度。影像组学方法在神经肿瘤学领域中的应用一直并可能继续处于这场革命的前沿。应用于常规和高级神经肿瘤学MRI数据的各种AI方法已经能够识别弥漫性胶质瘤的浸润边缘,区分假性进展和真实进展,并且比日常临床实践中使用的方法更好地预测复发和生存率。影像基因组学还将促进我们对癌症生物学的理解,允许以高空间分辨率对分子环境进行无创采样,从而能够对潜在异质性细胞和分子过程的系统理解。通过提供空间和分子异质性的体内标记物,基于人工智能的影像组学和影像基因组学工具有可能将患者分为更精确的初始诊断和治疗途径,并在个性化医疗时代实现更好的动态治疗监测。尽管仍存在重大挑战,但随着人工智能技术的进一步发展和临床应用的验证,在影像学实践中将发生巨大变化。
用户1279583
2022/02/28
1K0
Radiology:人工智能在神经肿瘤学中的新兴应用
转录组讲师带你读文献(3)-CYP46A1是GBM中的一个候选抑癌基因
我在我在04-转录组笔记推文任务列表(半年期)里面安排了6个经典综述和10篇转录组应用文献给大家,可惜愿意沉下心了认真苦学的并不多。(https://share.mubu.com/doc/14uneHKvPg)
生信技能树
2021/05/27
8250
转录组讲师带你读文献(3)-CYP46A1是GBM中的一个候选抑癌基因
公开数据单细胞挖掘6+分思路
今天和大家分享的是20年9月发表在cancers (Basel). (IF:6.126)杂志上的一篇文章,“Cancer-Specific Immune Prognostic Signature in Solid Tumors and Its Relation to Immune Checkpoint Therapies”,本篇研究中分析了4个单细胞RNA-Seq数据集和20个TCGA bulk RNA-Seq数据集中的免疫功能相关基因,使用了无监督聚类区分出主要的免疫功能类型。然后结合弹性网络回归和KM分析在不同肿瘤类型中确定了155个预后相关基因,并构建了癌症特异性预后免疫评分模型,最后使用了五种肿瘤的免疫检查点封锁疗法的公开数据进行模型验证。
生信交流平台
2022/09/21
5490
公开数据单细胞挖掘6+分思路
热点:泛癌+T细胞耗竭这么做可发1区~
T细胞构成了抗肿瘤免疫的主要组成部分。深入了解肿瘤微环境(TME)内的T细胞耗竭(TEX)异质性是克服TEX和改善临床上检查点阻断免疫疗法的关键。
作图丫
2022/12/04
5620
热点:泛癌+T细胞耗竭这么做可发1区~
Cell Reports研究思路--区分年轻成人肿瘤和晚发性癌症的基因组和分子特征筛选!
在最近几年的肿瘤特征筛选中,研究者的关注点往往在于区分不同癌症类型或者癌症生存相关的标志物,今天小编给大家带来的这篇文章中,作者以年龄作为关注点,系统地描述了发病年龄≤50岁的年轻成人肿瘤的基因组谱,并使用14种癌症类型的6000多例病例将其与晚发肿瘤进行比较,从而筛选到与年龄相关的分子驱动因素,可以指导青年成人癌症的精确诊断和治疗。文章发表于《Cell Reports》杂志上,题目为:Genomic and molecular features distinguish young adult cancer from later-onset cancer.
作图丫
2022/03/29
4580
Cell Reports研究思路--区分年轻成人肿瘤和晚发性癌症的基因组和分子特征筛选!
单基因泛癌+简单实验就能发表7分+
单基因泛癌发表高分的关键在于基因的选择。今天小编为大家带来一篇单基因泛癌+简单实验发表了7分+的Front. Immunol的文章,题目为Large-Scale Single-Cell and Bulk Sequencing Analyses Reveal the Prognostic Value and Immune Aspects of CD147 in Pan-Cancer。
作图丫
2022/06/24
5110
单基因泛癌+简单实验就能发表7分+
单细胞 RNA 测序揭示胶质瘤细胞分化相关基因
胶质瘤是起源于中枢神经系统的最常见的原发性肿瘤,目前没有适用于胶质母细胞瘤 (GBM) 和低级别胶质瘤 (LGG) 的预后模型。胶质瘤是由胶质瘤干细胞 (GSC) 驱动的,这主要是导致目前针对恶性胶质瘤的治疗策略失败的原因。考虑到 GSC 的多能性,它们可以分化成多个细胞亚群,从而导致细胞分化状态的高度异质性。有研究表明,GSCs 的分化状态可能与耐药性有关。但目前细胞分化的机制仍不清楚,因此确定与星形胶质细胞有关的 GSC 中涉及的分化相关基因 (DRG) 可能有助于识别新的生物标志物。本文旨在确定分化相关基因从而预测胶质瘤患者的预后和免疫治疗反应。
生信技能树jimmy
2022/03/14
1.2K0
单细胞 RNA 测序揭示胶质瘤细胞分化相关基因
推荐阅读
相关推荐
单一癌种综合分析也能发8分+SCI
更多 >
LV.0
这个人很懒,什么都没有留下~
目录
  • 虚拟 DOM 的优缺点?
  • Vue中key的作用
  • Vue组件data为什么必须是个函数?
    • Vue 的生命周期方法有哪些 一般在哪一步发请求
    • v-show 与 v-if 有什么区别?
    • Computed 和 Watch 的区别
    • 一般在哪个生命周期请求异步数据
    • diff算法
    • 过滤器的作用,如何实现一个过滤器
    • v-model 的原理?
    • 双向数据绑定的原理
    • 对SSR的理解
    • Vue 中 computed 和 watch 有什么区别?
    • Vue模版编译原理知道吗,能简单说一下吗?
    • 怎么缓存当前的组件?缓存后怎么更新
    • 双向绑定的原理是什么
    • 能说下 vue-router 中常用的 hash 和 history 路由模式实现原理吗?
    • 函数式组件优势和原理
    • Vue 为什么要用 vm.$set() 解决对象新增属性不能响应的问题 ?你能说说如下代码的实现原理么?
    • delete和Vue.delete删除数组的区别
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档