01Vue核心2

本文深入探讨了Vue.js中的MVVM架构,解释了为何Vue参考MVVM模型进行设计,以及如何实现数据代理。通过Object.defineProperty方法详细阐述了数据代理的工作原理,包括get和set的使用,以及在Vue实例中的应用。最后总结了数据代理在Vue中的重要性和益处。
摘要由CSDN通过智能技术生成

5.MVVM架构模型

1.为什么要学?

1.Vue作者在最开始设计Vue的时候,就在一定程度上参考了MVVM这个模型。
2.MVVM (Model-view-viewmodel) 是一种软件架构模式。

M(模型):对应data中的数据 Plain JS Object---一般js对象
V(视图):Vue代码中的Vue模板经过解析形成的dom页面
VM(视图模型):Vue缔造的实例对象
    Data Bindings 数据绑定:data数据经过Vue实例进行数据绑定,最后把数据摆在了想要呈现的页面的位置上。
    Dom Listeners dom监听者:页面上数据的改变能映射回data数据的改变,所以VM得时刻监听View视图(页面)上的内容。

图示:
在这里插入图片描述

2.Vue参考这个模型设计出来了什么?

MVVM和Vue的设计理念,如图所示:
在这里插入图片描述

3.正因为如此

所以外面经常用vm(ViewModel的缩写)这个变量名标识Vue实例。const vm = new Vue({})

4.在vm上都出现和vue模板可以直接使用(属性和方法)

1.data中写的一组一组的key-value,最后都出现在vm身上(成为了vm的属性)了。
Vue模板不仅能看见在创建Vue实例对象中自己写在data对象中的所有属性,并且所有vm身上的属性(Vue实例对象的所有属性和方法),Vue模板都能看得见。

2.所以Vue模板中,在{{}}中不仅可以写js表达式,还可以写数值常量计算,更能写vm中的所有的属性和方法(不仅仅是以$开头的)

3.不仅vm身上的,Vue模板可以用,而且出现在vm原型上东西(不仅仅是以$开头的属性和方法),Vue模板也可以直接用。

    <!-- 准备号一个容器 -->
    <div id="root">
        <h1>学校名称:{{name}}</h1>
        <h1>学校地址:{{address}}</h1>
        <h1>测试一下1:{{1+2}}</h1>
        <!-- $createElement已经出现在vm身上了,直接写就可以,不能写vm.$createElement-->
        <h1>测试一下:{{$createElement}}</h1>
        <h1>测试一下3:{{$emit}}</h1>
        <h1>测试一下4:{{_c}}</h1>
    </div>

    <script type="text/javascript">
        Vue.config.productionTip = false; 
        const vm = new Vue({
            el:'#root',
            data:{
               name:'尚硅谷',
               address:'北京'
            }
        });
        console.log(vm);  //输出的是vue实例
    </script>

6.数据代理

1.Object.defineProperty方法

1.Object.defineProperty方法简介

1.Vue底层里面很多都用到了它,比如说Vue劫持,数据代理,计算属性底层也用到了这个方法。
2.这个方法是给一个对象添加属性/定义属性的。

3.Object.defineProperty方法的语法:传三个参数。

  • 参数一:给添加属性的对象
  • 参数二:添加属性的名字
  • 参数三:配置项(是一个对象)—最常用的配置: value
Object.defineProperty(person,'age',{
    value:18
});

4.特点:新添加的属性是不能被枚举的。
1)一般方法添加对象属性,里面的属性可以被枚举

let person = {
    name:'张三',
    sex:'男',
    age:18
};

2)新方法添加对象属性,新添加的属性不可以被枚举(新添加的属性不参与遍历)

5.验证:
1)使用Object.keys()方法

  • Object.keys() 传入参数:一个对象
    作用:可以把传入对象里面所有属性的属性名提取出来变成一个数组

  • 使用console.log(Object.keys(person));验证:

    • 一般方法得到结果:[‘name’, ‘sex’,‘age’]
    • 新方法得到的结果:[‘name’, ‘sex’]

2)使用for in方法也可以得到上面的结果
代码

for(let key in person){
    console.log(person[key]);
};
2.一般方法添加对象属性的特点

1.可以被枚举
2.是可以随意的修改和删除对象的属性的。
图片:
在这里插入图片描述

3.Object.defineProperty方法在对象上添加/修改属性的特点

1.语法:Object.defineProperty(obj对象,prop属性,配置项)
2.配置项里的一般属性:

  • value:默认值(给对象属性赋值)
  • writable: 是否能够写/修改 true | false (默认为false)
  • configurable: 是否能够删除 true | false (默认为false)
  • enumerable:是否可枚举(遍历) true | false (默认为false)

代码:

Object.defineProperty(person,'age',{
    value:18,
    enumerable:true,   
    writable:true,
    configurable:TextTrackCueList
});

3.配置项里的特殊属性:

  • get:获取属性值
  • set:设置属性值
4.Object.defineProperty方法的get读取/set修改属性

1.get属性:

1)特点

  • 值是一个函数
  • 当有人读取defineProperty方法中obj对象的prop(添加的)属性时,get函数(getter)就会被调用,且返回值就是prop(添加的)属性值。
  • 可以将添加属性的属性值作为变量存储,读取时直接return 变量就可以读取到属性值。
  • 这样的属性值可以直接修改变量以改变属性值。(一般的方法直接修改变量,属性值不会改变)

2)在控制台可以通过直接修改变量,改变属性值。
代码:

<script>
    let number = 18;
    let person = {
        name:'张三',
        sex:'男',
    };
  
    Object.defineProperty(person,'age',{
        //当有人读取person的age属性时,get函数就会被调用,且返回值就是age值
        get:function(){
            return number;  //每次访问这个age都会触发get函数
        },

    }); 
    console.log(person);
</script>

3)直接修改number改变person中age的值:number = 23 ,此时person中的age属性就立即被修改。
图片:
在这里插入图片描述

4)注意:

  • 在控制台输出person对象时,刚开始只会显示{name:‘张三’,sex:‘男’} ,下拉后,会出现新添加的age属性,但是会以这种方式出现:age:(...) 只有当鼠标点击的时候,才会出现属性值。
  • 当鼠标放在age:(...)时会有一个英文提示:invoke property getter 映射属性getter ,getter指的是这里缩写的get配置项。
  • getter: get是属性名,它的属性值是函数,把它们放在一起就可以称为getter,以后把get函数称为getter,getter的返回值就是新添加的属性值,getter对象身上中还有一个为这个新增属性服务的get函数get age:f()
  • 图片
    在这里插入图片描述

5)区别于一般方法修改对象的属性值

  • 代码
let number = 18;
let person = {
    name:'张三',
    sex:'男',
    age:number
};
console.log(person);
  • 在控制台:如果直接修改number改变person中age的值:number = 23 ,此时再打印person,属性值并没有改变。必须还要再赋一遍值,才会改变。使用这个语句赋值person.age = number
    图片:
    在这里插入图片描述

2.set属性

1)特点

  • 值也是一个函数
  • 当有人修改defineProperty方法中obj对象的prop(添加的)属性时,set函数(setter)就会被调用,且会收到修改的具体值value。
  • 函数传的参数就是value,

2)代码

//当有人修改person的age属性是,set函数(setter)就会被调用,且会收到修改的具体值。
set:function(value){
    console.log('有人修改了age属性的值,修改后的值是value=',value);
    number = value;
}

3)注意:

  • 修改必须通过对象obj.属性名 = 修改的值/表示属性值的变量 来修改,set函数才会被调用。
  • 方法一:如果通过对象obj.属性名 = 修改的值的方法虽然调用了set函数,但并没有改变对象中的属性的属性值。因为属性是通过表示属性的变量来改变的,所以要配合使用表示属性的变量 = value 放在set函数中,才会改变对象的属性值。
  • 方法二:如果通过对象obj.属性名 = 表示属性值的变量的方法,既可以调用set函数,也会改变对象的属性值。前提是先要改变表示属性值的变量表示属性的变量 = 修改的值
  • 其实两个方法差不多。
  • 可如果利用get函数直接通过修改表示属性值的变量修改属性值,是不会调用set函数的

3.get和set的总结
1)get函数return的是属性值,属性值通常是可修改的变量,通过修改变量值的这一个步骤,就可以修改对象的属性值。

//控制台中
>number = 23   
>person 
>{age:'张三',sex:'男'}
> age:23
> name:'张三'
> sex:'男'

2)而一般方法的需要通过修改变量表示属性的变量=修改的值,再将修改后的变量重新赋值对象obj.属性名 = 修改后的变量两个步骤,才可以修改对象的属性值。

//控制台中
>number = 23
>{age:'张三',sex:'男'}
> age:18        //没改变
> name:'张三'
> sex:'男'

>person.age = number
>{age:'张三',sex:'男'}
> age:23
> name:'张三'
> sex:'男'

3)set方法要想被调用,只能是通过一般方法修改变量的步骤。而这种修改方式可以分为上面的两种情况。

  • 如果通过对象obj.属性名 = 修改的值的方法虽然调用了set函数,但并没有改变对象中的属性的属性值。因为属性是通过表示属性的变量来改变的,所以要配合使用表示属性的变量 = value 放在set函数中,才会改变对象的属性值。

    //set函数中
    set:function(value){
    console.log('有人修改了age属性的值,修改后的值是value=',value);
    number = value;
    }
    
    //控制台中
    >person.age = 23   (不写这条语句不能调用set)
    >  有人修改了age属性的值,修改后的值是value= 23
    < 23    set函数被调用
    
  • 如果通过对象obj.属性名 = 表示属性值的变量的方法,既可以调用set函数,也会改变对象的属性值。前提是先要改变表示属性值的变量表示属性的变量 = 修改的值

    //控制台中
    >number = 23
    >person.age = number (不写这条语句不能调用set)
    > 有人修改了age属性的值,修改后的值是value= 23
    < 23   //set函数被调用
    
5.Object.defineProperty方法总结

1.number 和person 是两个东西,但是借助defineProperty,让它
两之间产生关联。注意:容器和Vue实例之间也是这样的关系(所以,它们之间也是存在数据代理的关系)
2.person确实是一个对象,确实有age属性,但是age属性值是你
现用我现取。
3.靠get去取,靠set去改,并在set中把值拿回来。
在这里插入图片描述

2.何为数据代理?

1.数据代理定义:
通过一个对象代理对另一个对象中属性的操作(读/写)。
2.简单的数据代理:
有一个对象obj,它里面有属性x,如果访问x可以使用obj.x,如果想修改x可以使用obj.x=???
现在有一个对象obj2。希望obj2也能访问和修改obj里面的x,这时就会用到代理。
3.利用defineProperty实现数据代理

    <script>
        // 数据代理:通过一个对象代理对另一个对象中属性的读写操作
        let obj = {x:100};
        let obj2 = {y:200};
        //想通过obj2能读到x,并且还能修改x
        Object.defineProperty(obj2,'x',{   //和obj里面的x同名
            //get属性
            get(){
                return obj.x;   //以后如果有人通过obj2访问它里面的x时,其实给它的时obj.x
            },
            //set属性
            set(value){
                //如果set被调用,说明有人想更改obj2上的x
                obj.x = value;
            }
        })
    </script>

4.验证
在这里插入图片描述

3.Vue里面是如何应用数据代理的?验证

1.其实没有使用Vue的代码中,要实现数据代理是通过Object.defineProperty()实现的。
采用了Vue的代码,实现数据读取修改的原理就是数据代理————用Vue实例作为桥梁,让容器和data中数据建立联系。

2.验证一个Vue的实现是数据代理的原理:
1)通过vm读取data中的name,读的是data.name,如果有人想读取name时,getter工作,getter把data.name给过去。
2)通过vm修改data中的name,改的也是data.name,如果有人想修改name时,name对应的setter执行,把data.name改掉。
代码:

    <!-- 准备一个容器 -->
    <div id="root">
        <h2>学校名称:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>
    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false;   //阻止vue在启动时生成的生产提示

        //创建Vue实例--只传一个参数,参数的类型是配置对象
        const vm = new Vue({
            el:'#root',   //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串。
            data:{   //data中用于存储数据,数据供el所指定的容器去使用。值暂时先写成一个对象(以后会写成一个函数)
                name:'尚硅谷123',
                address:'洪福科技园'
            }
        });
    </script>

3.如何验证?
1)验证vm读出来的name到底是不是data.name:把data.name改成1,在vm中读取一下看是不是1。
*验证成功!

//在consloe中
>vm.name
<'尚硅谷123'
//在html中修改data.name:'尚硅谷456',在网页中刷新
//在consloe中
>vm.name
<'尚硅谷456'

2)验证通过vm修改name,看会不会把html中的data里面的name改掉。

注意:不能在控制台修改了vm.name='atguigi’后,直接在自己写的html中看。(html只是自己写的原始的数据)

  • 问题:在控制台,通过data.name拿不到data中的name,而且还会报错。(data is not defined)

  • 原因:data 不是全局都能用的变量,不可以直接通过data.name查看它的值。

  • 难题:如何拿到data.name?

  • 分析: data终归交给vm去用了,vm把data存到了哪里?————存到了自身身上,叫做vm._data。

    • 证明: vm._data 是不是等于Vue里面的data
        //在Vue实例外面定义一个data变量
        let data = {
            name:'尚硅谷123',
            address:'洪福科技园'
        }
        //再把这个变量传入进Vue实例中
        const vm = new Vue({
            el:'#root',   
            data
        });
    
      这样做了之后,有一个等式:vm._data==options.data==data
      其中:options是配置,options.data表示传入Vue的data
           data 是外面定义的变量data 
      只要在控制台中验证:vm._data===data,就可以证明Vue里面的data和vm._data是一个东西。
      验证为true。
    
  • 验证成功截图:
    在这里插入图片描述

4.数据代理总结
1)数据代理图示
在这里插入图片描述

2)总结

  • Vue中的数据代理:通过vm对象来代理data对象中属性的操作(读/写)
  • Vue中数据代理的好处:更加方便的操作data中的数据(所以vm.name可用)
  • 基本原理:通过Object.defineProperty()把data对象中所有属性添加到vm上,为每一个台南佳到vm上的属性,都指定一个getter/setter。在getter/setter内部去做读写操作,操作data中对应的属性。

5.注意:_data里面的做了一个数据劫持—要做一个响应式
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值