关于 vue原理和生命周期 1

最近由于各种原因又开始面试了,然后想把这方面关于vue做一个整理,以便于自己后续巩固复习~

若有不足,欢迎大佬补充并指证~

1、vue的生命周期钩子函数

   1)berforeCreate    new vue()触发的第一个钩子,现阶段data、methods、computed以及watch上的数据和方法都不能被访问。

    2)created   实力创建完成后触发,此阶段完成了数据观测,可是使用数据,更改数据。需要注意的是,在这个阶段更改数据的话,不会触发updated函数哦~,能获取初始数据,不能和dom进行交互,如果实在忍不住想访问dom,你用vm.$nextTick试试!

    3) beforeMount  挂在之前触发,此阶段templete已经导入渲染函数进行编译,而且此时虚拟dom已经创建完成,马上就开始渲染了.注意哈,此阶段更改数据的话和上一个一样,不会触发updated的哦

    4) mount  挂在完成后触发,此阶段真实dom挂载完成了,数据也双向绑定了,可以访问dom节点了,操作dom的话用$refs试试,结果会让你满意的。

    5)beforeUpdate  数据更新之前(响应式数据发生更新,虚拟dom重新渲染之前)触发,这个阶段可以进行数据更改,那会造成重渲染吗?答案当然是不会啦,放手干吧!

    6)updated 更新完成,dom完成更新触发。注意注意:避免在这个期间更改数据,不然就导致无线循环的更新啦。

    7)beforeDestroyed   实例销毁之前触发,当前阶段可以进行善后收尾工作,比如说清楚计时器之类的。

    8)destroyed  实例销毁之后触发剩一个dom空壳,组件被拆解了,数据绑定被卸除,监听被移出,子实例也统统被销毁。

2 理解一下MVVM,和MVC有什么区别

##哎呀,先说说MVC吧,MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式,这种模式一般用于应用程序的分层开发。

Model(模型) - 模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。

View(视图) - 视图代表模型包含的数据的可视化。Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。

1622125558(1).jpg
##再来说说MVVM吧,

MVVM是Model-View-ViewModel的简写,本质上就是MVC 的改进版。

即 MODEL 模型- VIEW 视图- VIEWMODEL 视图模型。

MODEL 指的是后端传递的数据。

VIEW 指的是所看到的页面。

VIEWMODEL mvvm模式的核心,它是连接view和model的桥梁。那么你得知道它做了什么,它做了两件事情,或者说它走了两个方向。

1)将 MODEL 转化成 VIEW,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。俗称联调接口,把后端返回的数据展示在前端页面。

2)将 VIEW 转化成 MODEL ,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。

上述两项都完成了,就是我们常说的,数据的双向绑定。

image.png

2、vue 2.0 如何实现的双向数据绑定(说白了就是考原理,有兴趣就去看看源码吧。)

先网上扒一张图过来


image.png

看图,首先就是data,在vue里,要实现对data的数据相应,利用Observer进行数据劫持。初始化数据之后,使用Object.definedProperty重新定义data中的所有属性,然后进行依赖收集,也就是图中的watcher(当前组件的watcher)

注释:Object.definedProperty(obj, prop, descriptor)
obj:必需。目标对象
prop:必需。需定义或修改的属性的名字
descriptor:必需。目标属性所拥有的特性

存取器了解一下,getter、setter

getter:当访问该属性时,该方法会被执行。函数的返回值会作为该属性的值返回
setter:当属性值修改时,该方法会被执行。该方法将接受唯一参数,即该属性新的参数值。

动动爪子试试

image.png

附一下代码:
var obj = {}; //定义一个新对象
var initVal = 'nihao'; //设置一个初始值
Object.defineProperty(obj,"newVal",{ //重定义数据,也就是数据劫持,数据代理
get:function (){//当获取值的时候触发的函数,也就是obj.newVal 的默认值是 nihao
return initVal;
},
set:function (value){//当设置值的时候触发的函数,设置的新值通过参数value拿到,如果设置新的值,obj.newVal就会发生改变
initVal = value;
}
});
//获取值
console.log( obj.newVal ); // 打印出来 hello
//设置值
obj.newVal = 'hao ge der';
console.log( obj.newVal ); //打印出来 hao ge der

打印结果 不信你自己试试


image.png

注意:当使用了getter或setter方法,不允许使用writable和value这两个属性
注意:不要在getter中再次获取该属性值,也不要在setter中再次设置改属性,否则会栈溢出

简单写个vue 数据代理和劫持
文件目录


image.png

简单示例


image.png

在js文件里面写个简单的vue 实例 进行数据代理 和数据劫持

class Vue {
// 构造器
constructor(params){
this.$options = params // vm
this._data = params.data //vm.data
this.initData() //初始化
}
initData(){
let data = this._data;
console.log(data) //结果如下
// {name: "xuxiansheng", message: "this is vue.js"}
// message: "this is vue.js"
// name: "xuxiansheng"
// proto: Object 原型

    //收集所有集合中的key 结果是一个数组 也就是收集watcher
    let keys = Object.keys(data);  //结果如下
    //  ["name", "message"]

    console.log(keys)
    // 遍历数组 使用objectDefine.property()对数据进行代理
    for(let i = 0; i < keys.length; i++){       
        // this指向vue实例   
        // 注意这里要用关键字let 而不要用var 否则会出现变量名提升 访问不到data中的数据
        // Object.definedProperty(obj, prop, descriptor)
        // obj:必需。目标对象
        // prop:必需。需定义或修改的属性的名字
        // descriptor:必需。目标属性所拥有的特性
        Object.defineProperty(this, keys[i], {
            // 可枚举?true  or false 
            // 至于for...in循环和Object.keys方法的区别,在于for...in包括对象继承自原型对象的属性,而Object.keys只包括对象本身的属性。 
            enumerable:true,
            // 是否可以删除目标属性或是否可以再次修改属性的特性
            configurable:true,
            get: function() { //获取属性值
                return  this._data[keys[i]]
            },
            set: function(value) { //设置新的值
                // 设置值
                data[keys[i]] = value
            }
        })
    } 
    
    // 为了实现data 数据的响应,需要对data中的数据进行劫持
    for(let i = 0;i < keys.length; i++){//遍历数组
        // 拿到data对象里面  key 为 keys[i]的值
        let value = data[keys[i]] 
        console.log(value) // xuxiansheng  this is vue.js
        Object.defineProperty(data, keys[i], {
            enumerable:true,
            configurable:true,
            get: function reactiveGetter(){
                console.log(`data的属性${keys[i]}的获取`);
                return value;
            },
            set: function reactiveSetter(val){
                console.log(`data设置属性${keys[i]}`)
                value = val;
            }
        })

    }
}

}
注意一下,get set函数里面打印不出来具体的属性值,所以reactiveGetter() reactiveSetter()这两个需要手动触发一下,才能打印里面的内容

你要想知道打印出来的是什么,,那就去浏览器的控制台输入命令 如下

image.png

有个东西值得好好注意一下,那就是没有进行数据劫持 只进行数据代理的时候,在浏览器控制台执行vm 回车 结果如下

image.png

但是做了数据劫持之后 如下图


image.png

vm明明是一个实例,可结果不一样。

所以数据代理劫持的目的就是为了实现vue里面的data数据访问的时候,如this.name 直接拿到的就是message的值,实际上this.name访问的应该是this.data.message

结合实际就是这么理解

image.png

以上是简单的数据劫持,如果遇到复杂的数据 那就进行扁平化处理,比如先判断当前数据的类型是复杂还是简单

image.png

简单数据注释掉 把它和复杂数据一起处理 封装一个方法
先判断数据类型


image.png

进行数据劫持


image.png

这个就暂时这样吧.....写太累了 后续整体更新吧

3 vue 2.x如何监测数据变化

那就是上面说的函数劫持了呗,重写了数组的方法(也就是上面提到的object.key()得到的数组),将data中的数据进行原型链的重写,这样一来调用api的时候就可以通知依赖更新了。
但是数组中如果包含引用类型的话,也就是复杂数据类型,然后进行递归遍历,实现数据监测,看不明白就自己动动爪子写写,好记性不如烂笔头

4 nextTick 实现原理是什么

在下一次dom更新循环结束之后执行延迟回调,这个主要使用了微任务和宏任务,不通执行环境分别尝试,promise mutationObserver setImmediate ,如果这三个都不行就用setTimeout 通过异步方法清空任务队列。

5 说说宏任务和微任务 (上个问题答了 这个问题紧随而来)

第一件事 先盗个图来


image.png
image.png

请自信告诉我,上面答应出来的是什么?

1、2、3、4? ×
2、4、1、3?×
2、4、3、1? ×
2、4、1 ? √ 想想为啥是这个答案

从一开始写代码的时候就知道一句话 js代码是从上往下一行一行执行的,所以很多人先入为主觉得输出应该是1234,可事实并非如此。

这就涉及到上面的宏任务 微任务了,结合上面宏任务微任务的图来看,同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。

当指定的事情完成时,Event Table会将这个函数移入Event Queue。主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。上述过程会不断重复,也就是面试官经常会问你的,什么是循环机制,这个就是Event Loop(事件循环)机制。

再偷个图

image.png

js异步有一个机制,就是遇到宏任务,先执行宏任务,将宏任务放入eventqueue,然后在执行微任务,将微任务放入eventqueue。

记住这俩规则:

宏任务一般是:包括整体代码script,setTimeout,setInterval。

微任务:Promise,process.nextTick。

所以上述代码就是,setTimeout是宏任务先执行但是特么它是异步的,所以要往下检查是不是有微任务,遇到了new Promise立即执行之后,打印console.log('2'),Promise.then()又被放入了微任务的队列里,所以先去执行了宏任务console.log('4'),执行完成之后才执行了setTimeout,所有主线程的任务栈执行完了才去执行了Promise.then()
这块有点复杂 暂时就理解这么多 后续补上吧

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容