详解vue中的数据初始化(initState)

下面vue.js教程栏目带大家了解一下vue中的数据初始化(initstate)。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

详解vue中的数据初始化(initState)

数据初始化

Vue 实例在建立的时候会运行一系列的初始化操作,而在这些初始化操作里面,和数据绑定关联最大的是 initState

首先,来看一下他的代码:

立即学习“前端免费学习笔记(深入)”;

function initState(vm) {    vm._watchers = [];    var opts = vm.$options;    if(opts.props) {        initProps(vm, opts.props); //初始化props    }    if(opts.methods) {        initMethods(vm, opts.methods); //初始化methods    }    if(opts.data) {        initData(vm); //初始化data    } else {        observe(vm._data = {}, true /* asRootData */ );    }    if(opts.computed) {        initComputed(vm, opts.computed); //初始化computed    }    if(opts.watch && opts.watch !== nativeWatch) {        initWatch(vm, opts.watch); //初始化watch    }}

登录后复制

在这么多的数据的初始化中,props、methods和data是比较简单的(所以我就不详细介绍了☺),而computed 和 watch则相对较难,逻辑较复杂,所以我下面主要讲下computed 和 watch(以下代码部分为简化后的)。

initState里面主要是对vue实例中的 props, methods, data, computed 和 watch 数据进行初始化。

在初始化props的时候(initProps),会遍历props中的每个属性,然后进行类型验证,数据监测等(提供为props属性赋值就抛出警告的钩子函数)。

在初始化methods的时候(initMethods),主要是监测methods中的方法名是否合法。

在初始化data的时候(initData),会运行 observe 函数深度遍历数据中的每一个属性,进行数据劫持。

在初始化computed的时候(initComputed),会监测数据是否已经存在data或props上,如果存在则抛出警告,否则调用defineComputed函数,监听数据,为组件中的属性绑定getter及setter。如果computed中属性的值是一个函数,则默认为属性的getter函数。此外属性的值还可以是一个对象,他只有三个有效字段set、get和cache,分别表示属性的setter、getter和是否启用缓存,其中get是必须的,cache默认为true。

function initComputed(vm, computed) {    var watchers = vm._computedWatchers = Object.create(null);    for(var key in computed) {        var userDef = computed[key];        var getter = typeof userDef === 'function' ? userDef : userDef.get;        //创建一个计算属性 watcher        watchers[key] = new Watcher(            vm,            getter || noop,            noop,            computedWatcherOptions        );        if(!(key in vm)) {            //如果定义的计算属性不在组件实例上,对属性进行数据劫持            //defineComputed 很重要,下面我们再说            defineComputed(vm, key, userDef);        } else {            //如果定义的计算属性在data和props有,抛出警告        }    }}

登录后复制

在初始化watch的时候(initWatch),会调用vm.$watch函数为watch中的属性绑定setter回调(如果组件中没有该属性则不能成功监听,属性必须存在于props、data或computed中)。如果watch中属性的值是一个函数,则默认为属性的setter回调函数,如果属性的值是一个数组,则遍历数组中的内容,分别为属性绑定回调,此外属性的值还可以是一个对象,此时,对象中的handler字段代表setter回调函数,immediate代表是否立即先去执行里面的handler方法,deep代表是否深度监听。

vm.$watch函数会直接使用Watcher构建观察者对象。watch中属性的值作为watcher.cb存在,在观察者update的时候,在watcher.run函数中执行。想了解这一过程可以看我上一篇的 vue响应式系统–observe、watcher、dep中关于Watcher的介绍。

function initWatch(vm, watch) {    //遍历watch,为每一个属性创建侦听器    for(var key in watch) {        var handler = watch[key];        //如果属性值是一个数组,则遍历数组,为属性创建多个侦听器        //createWatcher函数中封装了vm.$watch,会在vm.$watch中创建侦听器        if(Array.isArray(handler)) {            for(var i = 0; i 

computed

computed本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,第一次访问 computed 属性,才会计算新的值

下面将围绕这一句话来做解释。

上面代码中提到过,当计算属性中的数据存在与data和props中时,会被警告,也就是这种做法是错误的。所以一般的,我们都会直接在计算属性中声明数据。还是那个代码片段中,如果定义的计算属性不在组件实例上,会运行defineComputed函数对数据进行数据劫持。下面我们来看下defineComputed函数中做了什么。

function defineComputed(target, key, userDef) {//是不是服务端渲染var shouldCache = !isServerRendering();//如果我们把计算属性的值写成一个函数,这时函数默认为计算属性的getif(typeof userDef === 'function') {sharedPropertyDefinition.get = shouldCache ?//如果不是服务端渲染,则默认使用缓存,设置get为createComputedGetter创建的缓存函数createComputedGetter(key) ://否则不使用缓存,直接设置get为userDef这个我们定义的函数userDef;//设置set为空函数sharedPropertyDefinition.set = noop;} else {//如果我们把计算属性的值写成一个对象,对象中可能包含set、get和cache三个字段sharedPropertyDefinition.get = userDef.get ?shouldCache && userDef.cache !== false ?//如果我们传入了get字段,且不是服务端渲染,且cache不为false,//设置get为createComputedGetter创建的缓存函数createComputedGetter(key) : //如果我们传入了get字段,但是是服务端渲染或者cache设为了false,设置get为userDef这个我们定义的函数userDef.get ://如果没有传入get字段,设置get为空函数noop;//设置set为我们传入的传入set字段或空函数sharedPropertyDefinition.set = userDef.set ?userDef.set :noop;}//虽然这里可以get、set都可以设置为空函数//但是在项目中,get为空函数对数据取值会报错,set为空函数对数据赋值会报错//而computed主要作用就是计算取值的,所以get字段是必须的//数据劫持Object.defineProperty(target, key, sharedPropertyDefinition);}

登录后复制

在上一篇的 vue.js教程 中,我有关于Watcher的介绍中提到,计算属性 watcher实例化的时候,会把options.lazy设置为true,这里是计算属性惰性求值,且可缓存的关键,当然前提是cache不为false。

cache不为false,会调用createComputedGetter函数创建计算属性的getter函数computedGetter,

先来看一段代码

function createComputedGetter(key) {    return function computedGetter() {        var watcher = this._computedWatchers && this._computedWatchers[key];        if(watcher) {            if(watcher.dirty) {            //watcher.evaluate中更新watcher的值,并把watcher.dirty设置为false            //这样等下次依赖更新的时候才会把watcher.dirty设置为true,            //然后进行取值的时候才会再次运行这个函数                watcher.evaluate();            }            //依赖追踪            if(Dep.target) {                watcher.depend();            }            //返回watcher的值            return watcher.value        }    }}//对于计算属性,当取值计算属性时,发现计算属性的watcher的dirty是true//说明数据不是最新的了,需要重新计算,这里就是重新计算计算属性的值。Watcher.prototype.evaluate = function evaluate() {    this.value = this.get();    this.dirty = false;};//当一个依赖改变的时候,通知它updateWatcher.prototype.update = function update() {    //三种watcher,只有计算属性 watcher的lazy设置了true,表示启用惰性求值    if(this.lazy) {        this.dirty = true;    } else if(this.sync) {        //标记为同步计算的直接运行run,三大类型暂无,所以基本会走下面的queueWatcher        this.run();    } else {        //将watcher推入观察者队列中,下一个tick时调用。        //也就是数据变化不是立即就去更新的,而是异步批量去更新的        queueWatcher(this);    }};

登录后复制

当options.lazy设置为true之后(仅计算属性watcher的options.lazy设置为true),每次依赖更新,都不会主动触发run函数,而是把watcher.dirty设置为true。这样,当对计算属性进行取值时,就会运行computedGetter函数,computedGetter函数中有一个关于watcher.dirty的判断,当watcher.dirty为true时会运行watcher.evaluate进行值的更新,并把watcher.dirty设置为false,这样就完成了惰性求值的过程。后面只要依赖不更新,就不会运行update,就不会把watcher.dirty为true,那么再次取值的时候就不会运行watcher.evaluate进行值的更新,从而达到了缓存的效果。

综上,我们了解到cache不为false的时候,计算属性都是惰性求值且具有缓存性的,而cache默认是true,我们也大多使用这个默认值,所以我们说 computed本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,第一次访问 computed 属性,才会计算新的值。

相关推荐:2020年前端vue面试题大汇总(附答案)vue教程推荐:2020最新的5个vue.js视频教程精选

更多编程相关知识,请访问:vue.js教程!!

以上就是详解vue中的数据初始化(initState)的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/3023030.html

(0)
上一篇 2025年3月13日 06:02:06
下一篇 2025年3月1日 11:58:32

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 深入了解vue中的计算属性

    下面vue.js教程栏目带大家了解一下vue中的计算属性。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 一、什么是计算属性 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且…

    2025年3月13日
    200
  • 浅谈vue中axios的封装

    下面vue.js教程栏目带大家了解一下vue中axios的封装。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 vue中axios的封装 第一步还是先下载axios cnpm install axios -S 登录后复制 …

    2025年3月13日
    200
  • vue如何动态绑定class?方法介绍

    Vue.js 的核心是一个响应的数据绑定系统,它允许我们在普通 HTML 模板中使用特殊的语法将 DOM “绑定”到底层数据。 被绑定的DOM 将与数据保持同步,每当数据有改动,相应的DOM视图也会更新。基于这种特性,通过vue.js动态绑…

    2025年3月13日
    200
  • 详解Vue中动态添加类名的方法

    能够向组件添加动态类名是非常强大的功能。它使我们可以更轻松地编写自定义主题,根据组件的状态添加类,还可以编写依赖于样式的组件的不同变体。 添加动态类名与在组件中添加 prop :class=”classname”一样…

    2025年3月13日
    200
  • vue中递归组件的实现方法介绍(附实例:三级菜单)

    下面vue.js教程栏目通过实例制作一个三级菜单,来介绍vue中递归组件的实现方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 js里面有递归算法,同时,我们也可以利用props来实现vue模板的递归调用,但是前提是组…

    2025年3月13日
    200
  • vue中路由之间如何通讯?方法介绍

    下面vue.js教程栏目给大家介绍一下vue中向路由组件传递props的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 父子间的组件通讯是通过props和$emit来实现的,那么路由之间的通讯呢,往下看: 我现在再w…

    2025年3月13日 编程技术
    200
  • vue+webpack2实现路由懒加载的方法介绍

    下面vue.js教程栏目给大家介绍一下vue+webpack2实现路由的懒加载的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路…

    2025年3月13日
    200
  • vue2.0子组件中怎么改变父组件中的值 ?

    下面vue.js教程栏目给大家介绍一下vue2.0中子组件通过v-modal改变父组件中值的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 vue2.0中子组件通过v-modal改变父组件中的值 父组件代码:   p…

    2025年3月13日
    200
  • vue watch用法是什么

    vue watch用法是:1、当fullName值变化时,watch监听到并且执行;2、watch执行handler方法和immediate属性;3、使用deep属性,深度监听,常用语对象下面属性的改变。 【相关文章推荐:vue.js】 v…

    2025年3月13日
    200
  • vuex有什么用?

    vuex是基于vue框架的一个状态管理库,可以管理复杂应用的数据状态,可以方便的实现组件之间的数据共享,例兄弟组件的通信、多层嵌套的组件的传值等等;它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。…

    2025年3月13日
    200

发表回复

登录后才能评论