vue中定义的data为什么是函数

目录
  • 一、new Vue场景
  • 二、组件场景
  • 总结

高频面试题:vue中的data为啥是函数?

答案是:是不是一定是函数,得看场景。并且,也无需担心什么时候该将data写为函数还是对象,因为vue内部已经做了处理,并在控制台输出错误信息。

一、new Vue场景

new Vue({
  el: "#app",
  // 方式一:对象
  data: {
    obj: {
      name: "qb",
    }
  },
  // 方式二:工厂函数
  // data () {
  //   return {
  //     obj: {
  //       name: "qb",
  //     }
  //   }
  // },
  template: `<div>{{obj.name}}</div>`
});

这种场景主要为项目入口或者多个html页面各实例化一个Vue时,这里的data即可用对象的形式,也可用工厂函数返回对象的形式。因为,这里的data只会出现一次,不存在重复引用而引起的数据污染问题。

二、组件场景

Vue.component("countComponent", {
  data() {
    return {
      count: 1
    };
  },
  template: `<div>
    <button @click='changeCount'>递增</button>
    <span>{{count}}</span>
  </div>`,
  methods: {
    changeCount() {
      this.count++;
    }
  }
});

new Vue({
  el: "#app",
  template: `<div>
    <countComponent></countComponent>
    <countComponent></countComponent>
  </div>`
});

首先定义全局组件countComponent,然后将该组件重复使用两次,当定义全局组件的时候,会执行Vuecomponent方法:

// ASSET_TYPES定义在文件shared/constants.js文件中
export const ASSET_TYPES = [
  'component',
  'directive',
  'filter'
]

// 以下ASSET_TYPES遍历绑定方法的定义在initGlobalAPI(Vue)全局方法挂载阶段完成
import { ASSET_TYPES } from 'shared/constants'
import { isPlainObject, validateComponentName } from '../util/index'
export function initAssetRegisters (Vue: GlobalAPI) {
  /**
   * Create asset registration methods.
   */
  ASSET_TYPES.forEach(type => {
    Vue[type] = function (
      id: string,
      definition: Function | Object
    ): Function | Object | void {
      if (!definition) {
        return this.options[type + 's'][id]
      } else {
        /* istanbul ignore if */
        if (process.env.NODE_ENV !== 'production' && type === 'component') {
          validateComponentName(id)
        }
        if (type === 'component' && isPlainObject(definition)) {
          definition.name = definition.name || id
          definition = this.options._base.extend(definition)
        }
        if (type === 'directive' && typeof definition === 'function') {
          definition = { bind: definition, update: definition }
        }
        this.options[type + 's'][id] = definition
        return definition
      }
    }
  })
}

这里的场景是component,那么会执行到definition = this.options._base.extend(definition)进行组件构造函数的实现,这里的this.options._base就是构造函数Vueextend方法为:

//  Vue.extend 方法的定义在initGlobalAPI(Vue)全局方法挂载阶段完成
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)
    }
    Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
    Sub.cid = cid++
    Sub.options = mergeOptions(
      Super.options,
      extendOptions
    )
    // ...
  }
}

定义完组件构造函数Sub后,在为其合并options时,会执行到mergeOptions

/**
 * Merge two option objects into a new one.
 * Core utility used in both instantiation and inheritance.
 */
export function mergeOptions (
  parent: Object,
  child: Object,
  vm?: Component
): Object {
  // ...
  const options = {}
  let key
  for (key in parent) {
    mergeField(key)
  }
  for (key in child) {
    if (!hasOwn(parent, key)) {
      mergeField(key)
    }
  }
  function mergeField (key) {
    const strat = strats[key] || defaultStrat
    options[key] = strat(parent[key], child[key], vm, key)
  }
  return options
}

在当前例子中,会通过const options = {}定义一个空对象,然后分别将parentchild上的属性合并到options上,此时data的合并策略为:

strats.data = function (
  parentVal,
  childVal,
  vm
) {
  if (!vm) {
    if (childVal && typeof childVal !== 'function') {
      process.env.NODE_ENV !== 'production' && warn(
        'The "data" option should be a function ' +
        'that returns a per-instance value in component ' +
        'definitions.',
        vm
      );

      return parentVal
    }
    return mergeDataOrFn(parentVal, childVal)
  }

  return mergeDataOrFn(parentVal, childVal, vm)
};

这里childVal类型为object,即typeof childVal !== 'function'成立,进而在开发环境会在控制台输出警告并且直接返回parentVal,说明这里压根就没有把childVal中的任何data信息合并到options中去。

总结

vue中已经帮我们控制台输出警告,并且不会让组件中的data合并到options中去,那么,很友好的处理了开发者的强行将data写成对象的可能性。

到此这篇关于vue中定义的data为什么是函数的文章就介绍到这了,更多相关vue中data为什么是函数内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 解析vue data不可以使用箭头函数问题

    首先需要明确,a() {}和 b: () => {}是不同的 let obj = { a() {}, // 相当于 a:function() {}, b: () => {} } 1 VUE.js 源码解析 注意此处只设计核心代码 这段代码也是UMD实现原理,本文这里不是重点,有兴趣的可以自行探究. (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined'

  • 详解Vue的组件中data选项为什么必须是函数

    官方解释 data 必须是函数 构造 Vue 实例时传入的各种选项大多数都可以在组件里使用.只有一个例外:data 必须是函数.实际上,如果你这么做: Vue.component('my-component', { template: '<span>{{ message }}</span>', data: { message: 'hello' } }) 那么 Vue 会停止运行,并在控制台发出警告,告诉你在组件实例中 data 必须是一个函数.但理解这种规则为何存在也是很有益处的,

  • vue实现动态给data函数中的属性赋值

    目录 vue动态给data函数中的属性赋值 vue给data中的数据赋值报错 问题背景 分析 解决方案 vue动态给data函数中的属性赋值 1.首先创建一个监视器,用来监视相关的属性 2.当这个相关的属性被修改的时候,在监视器中的handler函数中写处理逻辑即可 vue给data中的数据赋值报错 TypeError: Cannot set property ‘tableData‘ of undefined 问题背景 最近刚入门vue,有个典型的场景,也是简单的坑.就是需要通过axios请求数

  • 你知道vue data为什么是一个函数

    官网解释:当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例.如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象.我看到这个问题的时候是我面试的时候一个面试官问我的,当时懵了,从来没有想过为什么,只知道代码需要这么写.最近有空再来了解一下这部分的原理内容.有两个我比较喜欢回答 1.是为了在重复创建实例的时候避免

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

    前言 我们需要先复习下原型链的知识,其实这个问题取决于 js ,而并非是 vue . function Component(){ this.data = this.data } Component.prototype.data = { name:'jack', age:22, } 首先我们达成一个共识(没有这个共识,请补充下 js 原型链部分的知识): 实例它们构造函数内的this内容是不一样的. Component.prototype ,这类底下的方法或者值,都是所有实例公用的. 解开疑问 基

  • Vue的data为啥只能是函数原理详解

    目录 前言 1.Vue3中的data 2.vue中的data 3.证明data是函数以及原理实现 4.如果data必须是一个对象呢? 前言 在学习vue的时候vue2只有在组件中严格要求data必须是一个函数,而在普通vue实例中,data可以是一个对象,但是在vue3出现后data必须一个函数,当时看着官方文档说的是好像是对象的引用问题,但是内部原理却不是很了解,今天通过一个简单的例子来说明为啥data必须是一个函数 参考(vue2data描述) 参考: (vue3data描述) 1.Vue3

  • vue中定义的data为什么是函数

    目录 一.new Vue场景 二.组件场景 总结 高频面试题:vue中的data为啥是函数? 答案是:是不是一定是函数,得看场景.并且,也无需担心什么时候该将data写为函数还是对象,因为vue内部已经做了处理,并在控制台输出错误信息. 一.new Vue场景 new Vue({ el: "#app", // 方式一:对象 data: { obj: { name: "qb", } }, // 方式二:工厂函数 // data () { // return { //

  • vue中父子组件传值,解决钩子函数mounted只运行一次的操作

    因为mounted函数只会在html和模板渲染之后会加载一次,但是在子组件中只有第一次的数据显示是正常的,所以需要再增加一个updated函数,在更新之后就可以重新进行取值加载,完成数据的正常显示. beforCreate(创建之前) Created(创建之后) beforMount(载入之前) Mounted(载入之后) beforUpdate(更新之前) Updated(更新之后) beforDestroy(销毁之前) Destroyed(销毁之后) activate(keep-alive组

  • vue中的生命周期及钩子函数

    目录 1.什么是生命周期 2.vue 的生命周期 3.生命周期钩子函数 1.什么是生命周期 Vue 实例有一个完整的生命周期,也就是从开始创建.初始化数据.编译模板.挂载 Dom.渲染 → 更新 → 渲染.卸载等一系列过程,我们称这是 Vue 的生命周期.通俗说就是 Vue 实例从创建到销毁的过程,就是生命周期. 在 Vue 的整个生命周期中,它提供了一系列的事件,可以让我们在事件触发时注册 js 方法,可以让我们用自己注册的 js 方法控制整个大局,在这些事件响应方法中的 this 直接指向的

  • 基于Vue中this.$options.data()的this指向问题

    目录 this.$options.data()的this指向问题 vue文档中有关于data的指向问题的解释 vue骚操作之this.$options.data() 重置vue组件的data数据 小结一下 this.$options.data()的this指向问题 项目里遇到一个问题,用this.$options.data()重置组件data时报错,原因是因为form里的rule规则采用了this写法. 如下: rules: {         code: [this.$rules.requir

  • vue中如何初始化data数据

    目录 如何初始化data数据 vue程序初始化流程 初始化 改写的原因 流程实现 源码流程 初始化流程 如何初始化data数据 后台管理系统中,新建和编辑使用同一个页面,常常需要初始化data数据. form: { id: 0, name: '', place: '', number: '', admin_uid: '', is_audit: 2, contact: '', sort: '', is_network: 2, network_type: 1, is_projector: 2, is

  • vue中如何给data里面的变量增加属性

    目录 给data里面的变量增加属性 vue框架是使用mvvm模式 我废话不多说直接上方法了 给data中的响应式对象动态添加属性 给data里面的变量增加属性 vue框架是使用mvvm模式 里面有一种通知机制 如果数据发生了变化 就会通过 视图进行更新 那是不是这样呢 我们只要把vue中data中的值发生变化dom树就会随时更新呢 <div id="app">             <ul>                 <li v-for="

  • Vue中定义全局变量与常量的各种方式详解

    前言 本文主要跟大家介绍了关于Vue定义全局变量与常量的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍: 我想要定义一个变量, 在项目的任何地方都可以访问到, 不需要每一次使用的时候, 都引入. 尝试1: 创建 global.js 并且在其中定义 let a = 10; 在入口文件中引入 global.js import './global.js' 在项目中使用: a // 报错 发现报错了, a 并没有定义. 为什么? 这个涉及到模块作用域: 1 每一个 js 都相当于

  • VUE v-for循环中每个item节点动态绑定不同函数的实例

    一. 业务场景: 一个title 处 可能有 一个或多个按钮, 按钮对应不同的响应事件 二. 思路 : 按钮个数 根据传入的数据length 来循环渲染, 每条数据对应的事件名称 通过动态绑定 三. 封装组件 1. 视图层面 2. 代码部分 2.1 结构部分 <!-- 多个button组件--> <titleAddBtn :addBtnList="addBtnList" @clkCallBk="listenCall"></titleAd

  • VUE中的自定义指令钩子函数讲解

    目录 自定义指令钩子函数 自定义指令 先上官方解释 小贴士 钩子函数运行顺序 自定义指令钩子函数 自定义指令 除了VUE 内置指令外,VUE也支持我们自定义注册指令,分为局部和全局注册 但这些想必大家都不陌生,其中官方API也是写的明明白白 官方API点这里 而且自定义指令也会极大程度上帮助我们日常的编程,但这是很有意思的事情出现了,就是钩子函数,很多老铁都弄不明白这五个函数的具体区别 先上官方解释 bind:只调用一次,指令第一次绑定到元素时调用.在这里可以进行一次性的初始化设置. inser

  • vue中data的基础汇总

    目录 vue中如何重置data 组件中的data为什么是一个函数 为什么new Vue里的data可以是一个对象 vue中如何重置data 重置data需要了解3个小知识点 (1)this.$data获取组件当前状态的data对象 (2)this.$options.data获取组件初始状态的data对象 (3)Object.assign()方法用于将所有可美剧属性的值从一个或者多个源对象复制到目标对象,并返回目标对象. Object.assign(target,source1,source2,.

随机推荐