Vue | Object.defineProperty()、数据代理、计算属性、监视属性

 

目录

一、Object.defineProperty()

二、简单的数据代理小例子

三、数据代理

四、计算属性(Computed)

五、监视属性(Computed) 


说到Object.defineProperty()这个方法,它是给大家可不要小瞧它,Vue底层很多地方都用到了它。比如:数据劫持、数据代理、计算属性等等。

一、Object.defineProperty()

     <script>
        let number = 18;
        let person = {
            name:'王仕丹'
        }
        Object.defineProperty(person,'age',{
            enumerable:true,//控制属性是否可以被枚举,默认为false
            writable:true,  //控制属性是否可以被修改,默认为false
            configurable:true,//控制属性是否可被删除,默认为false
            get(){
                console.log('有人读取age')
                return number
            },
            set(value){
                console.log('有人修改age')
                number = value
            }
        })
    </script>

Object.defineProperty()的第一个参数是给谁添加属性,第二个参数是添加什么属性,第三个参数是配置项,里面有enumerable、writable、configurable、getter、setter等。

工作原理就是当有人读取这个属性时,会把返回值作为属性值传出去,当有人修改这个属性时,会把修改的这个新值赋值给这个变量。

二、简单的数据代理小例子

   <script>
        Vue.config.productionTip = false
        let obj = {
            x:1
        }
        let obj2 = {
            y:2
        }
        Object.defineProperty(obj2,'x',{
            get(){
                return obj.x
            },
            set(value){
                obj.x = value
            }
        })
    </script>

 当有人读取obj2.x时,getter会把obj.x返回出去,当有人修改obj2.x时,setter会把新值赋值给obj.x。

三、数据代理

我们就浅说一下vue中的数据代理吧~

举个栗子:

<body>
    <div id="root">
        <h2>学校:{{school}}</h2>
        <h2>地址:{{address}}</h2>
    </div>
    <script>
        Vue.config.productionTip = false
        const vm = new Vue({
            el:'#root',
            data:{
                school:'阜阳师范大学',
                address:'颍州区'
            }
        })
    </script>
</body>

我们可以看到,我们通过vm可以访问到data中的school属性,也可以通过vm修改data中的school属性值,这是为什么呢?

其实它底层原理是Object.defineProperty()这个方法,我们先来看一下数据代理的原理图:

当我们创建vm这个实例对象时,Vue会把data中的数据原封不动的赋值给_data,并且data会有这样一个动作,就是往vm实例对象身上添加data对象中的所有属性,且每一个属性都会有自己的getter和setter。

当有人读取这个属性时,调用getter,getter读取data中的这个属性,并把data中的这个属性的属性值return出去,也就是作为返回值。

get(){
   return '我是你想要的data中的属性值'
}

当有人修改这个属性时,调用setter,setter会把你修改的新值在内部做一个赋值操作,也就是把原data中的属性值修改了,data中的数据修改了,当然页面也会重新渲染。

set(value){
    school = value
}

四、计算属性(Computed)

emmm……说到计算属性呢……我来想想要怎么来讲……

首先我们先来搞明白什么是计算属性吧~

定义:要用的属性data中不存在,要通过已有属性计算得来。

之前我们也说了,计算属性底层的原理也是借助了Object.defineProperty()这个方法提供的getter和setter,那么它这两个函数在什么时候执行呢?

<body>
    <div id="root">
        姓:<input type="text" v-model="firstName"><br><br>
        名:<input type="text" v-model="lastName"><br><br>
        全名:<span>{{fullName}}</span>
    </div>
    <script>
        Vue.config.productionTip = false

        const vm = new Vue({
            el: '#root',
            data:{
                firstName: '张',
                lastName: '三'
            },
            computed:{
                fullName:{
                    get(){
                        console.log('get被调用了')
                        return this.firstName +'-'+ this.lastName
                    }
                }
            }
        })
        console.log(vm)
    </script>
</body>

我在get函数中输出打印了一下,方便我们观察get函数什么时候被调用了。

可以看到,我们没有任何操作,但是在初始化的时候就已经调用了一次。那如果,我们在页面中用了很多次fullName呢?我们来看看。

    <div id="root">
        姓:<input type="text" v-model="firstName"><br><br>
        名:<input type="text" v-model="lastName"><br><br>
        全名:<span>{{fullName}}</span>
        全名:<span>{{fullName}}</span>
        全名:<span>{{fullName}}</span>
    </div>

可以看到,不管我们使用多少次fullName这个计算属性,getter只被调用了一次。也不卖兜子了,那是因为我们的coputed中有缓存机制,当我们的计算属性所依赖的属性没有发生变化时,就会继续复用我们之前的数据。 这也大大提高了Vue的效率,这也是computed的一大优势!!!

好了,我们来总结一下get函数在计算属性中,什么时候执行了。

  • 初次读取时会执行一次
  • 当依赖的数据发生改变时会被再次调用

在我们前端的面试中,经常也会问到这样的问题:与methosd实现相比,computed会有什么优势呢?之前我们也说了,computed内部有缓存机制(复用),效率更高,调试方便。

 注意:

  1. 计算属性最终会出现在vm上,直接读取使用即可
  2. 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生变化

五、监视属性(Computed) 

我们先来看一个小案例。

<body>
    <div id="root">
        <h2>今天天气很{{info}}</h2>
        <button @click = 'isHot = !isHot'>点击切换天气</button>
    </div>
    <script>
        Vue.config.productionTip = false
        new Vue({
            el:'#root',
            data:{
                isHot:true
            },
            computed:{
                info(){
                    return this.isHot ? '炎热':'凉爽'
                }
            },
            watch:{
                isHot:{
                    // deep:true,
                    immediate:true,
                    handler(oldvalue,newvalue){
                        console.log('isHot被修改了',oldvalue,newvalue)
                    }
                }
            }
        })
    </script>
</body>

 这是一个关于切换天气的一个小案例,添加了一个watch的配置项,当我们监视的属性【isHot】发生变化时,就会调用handler函数,函数中有两个参数,分别是变化前的旧值和变化后的新值。其中,有两个属性。【deep:true】,是否开启深度监视?vue是具备深度监视这个功能的,但是需要我们把【deep】从false改为true;还有一个属性【immediate:true】,是否立即执行?当我们的这个监视过程中,如果是一个漫长的过程,可能要等很久,如果把【immediate】从默认的false改为true,它就不会等这个监视结束,会立即执行。

除了在new Vue里这样用对象的形式写之外,我们还可以这样写:

        vm.$watch('isHot',(ewvalue,oldvalue)=>{
            console.log('isHot被修改了',newvalue,oldvalue)
        })

其实这种写法其中的handler函数我用了简写,只要不需要【immediate】和【deep】配置项,我们都可以简写,比如第一种写法:

                isHot(newvalue,oldvalue){
                    console.log('isHot被修改了',newvalue,oldvalue)
                }

好了好了,今天就说到这里。拜比~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值