Vue 面试知识点总结

栏目: JavaScript · 发布时间: 5年前

内容简介:本文内容来自网络,整理出来分享于大家~~参考至小册先来一张总体图,然后我们对每一部分详细分析。

本文内容来自网络,整理出来分享于大家~~

一、剖析 Vue.js 内部运行机制

参考至小册 剖析 Vue.js 内部运行机制

先来一张总体图,然后我们对每一部分详细分析。

Vue 面试知识点总结

1、初始化与挂载

Vue 面试知识点总结

new Vue 之后回调用一个 _init 方法去初始化,会初始化 datapropsmethods声明周期watchcomputed事件 等。其中最重要的一点就是通过 Object.defineProperty 来设置 gettersetter ,从而实现数据的 【双向绑定响应式】【依赖收集】

初始化完之后会调用一个 $mount 来实现挂载。如果是运行时编译,则不存在 render function ,存在 template 的情况需要重新编译。(我理解的意思:最开始我们需要去解析编译 template 中的内容,实现依赖收集和数据绑定,最后会生成一个 render function .但是如果是运行时候比如响应数据的更改等,则不会在生成 render function ,而是通过 diff 算法直接操作虚拟 DOM ,实现正式结点的更新)。

2、响应式系统的实现原理

Vue是一款MVVM的框架,数据模型仅仅是普通的js对象,但是在操作这些对象的时候确可以及时的响应视图的变化。依赖的就是Vue的【响应式系统】。

面试题 —— 你了解Vue的MVVM吗?

MVVM包含三层:模型层Model,视图层View,控制层ViewModel.

Vue 面试知识点总结

联系:

  • 视图层变化可以被viewModel监听到,从而更改Model中的数据。是通过 DOM事件监听 实现。
  • Model层发生变化,可以被viewModel响应到view层,从而更新视图。是通过 数据绑定

总之:DOM事件监听和数据绑定是MVVM的关键。 DOM Listeners 监听页面所有View层DOM元素的变化,当发生变化, Model 层的数据随之变化; Data Bindings 监听 Model 层的数据,当数据发生变化, View 层的DOM元素随之变化。

(1)Object.defineProperty

首先我们来介绍一下 Object.defineProperty,Vue.js就是基于它实现「响应式系统」的。

Object.defineProperty(obj, prop, descriptor);

descriptor的一些属性,简单介绍几个属性:

  • enumerable,属性是否可枚举,默认 false。
  • configurable,属性是否可以被修改或者删除,默认 false。
  • get,获取属性的方法。
  • set,设置属性的方法。
  • writable,当且仅当该属性的writable为true时,value才能被赋值运算符改变。默认为 false。
var o = {}; // 创建一个新对象

// 【1】在对象中添加一个属性与数据描述符的示例
Object.defineProperty(o, "a", {
  value : 37,
  writable : true,
  enumerable : true,
  configurable : true
});

// 对象o拥有了属性a,值为37

// 【2】在对象中添加一个属性与存取描述符的示例
var bValue;
Object.defineProperty(o, "b", {
  get : function(){
    return bValue;
  },
  set : function(newValue){
    bValue = newValue;
  },
  enumerable : true,
  configurable : true
});

o.b = 38;
// 对象o拥有了属性b,值为38

// o.b的值现在总是与bValue相同,除非重新定义o.b

(2)实现数据的观察(observer)

这是响应式系统最为重要的一步。利用的便是我们上面提到的 Object.defineProperty

实现一个简单的对数据的getter和setter监听:

// 遍历数据对象的每个属性,这里我们只做了一层,实际上会使用递归去处理深层次的数据
// 这里为了我们的方便理解,就假设是单层对象
function observer (value) {
    if (!value || (typeof value !== 'object')) {
        return;
    }
    
    Object.keys(value).forEach((key) => {
        defineReactive(value, key, value[key]);
    });
}

// 函数模拟视图更新
function cb (val) {
    console.log("视图更新啦~", val);
}

// 数据对象成员的响应式监听
function defineReactive (obj, key, val) {
    Object.defineProperty(obj, key, {
        enumerable: true, // 可枚举
        configurable: true, // 可配置
        get: function reactiveGetter () {
            return val;     // 当使用到我们的这个属性的时候会触发get方法,这里用来依赖收集,我们之后实现
        },
        set: function reactiveSetter (newVal) {
            // 监听数据的修改,模拟视图更新,其实这里的过程相当的复杂,diff是一个必经过程
            if (newVal === val) return;
            val = newVal;
            cb(newVal);
        }
    });
}


class Vue {
    constructor(options) {
        this._data = options.data; // 获取数据对象
        observer(this._data); // 实现对数据中每个元素的观察,即为每个属性去设置get和set。
    }  
}


// 测试案例
let o = new Vue({
    data: {
        test: "I am test."
    }
});
o._data.test = "hello,test.";

上面我们实现的是一个简单的响应式原理案例,我们只是实现了对数据对象的观察。当我们的数据使用和被修改的时候会调用我们的自定义get和set方法。下面我们去了解一下,数据【依赖收集】。

(3)依赖收集

为什么要进行依赖收集呢?

new Vue({
    template: 
        `<div>
            <span>{{text1}}</span> 
            <span>{{text2}}</span> 
        <div>`,
    data: {
        text1: 'text1',
        text2: 'text2',
        text3: 'text3'
    }
});

上面例子中,text1,text2使用了一次,text3未使用。

如果我们对某一个数据进行了修改,那么我们应该知道的哪些地方使用了该数据,为了我们视图的更新做好准备。

「依赖收集」会让 text1 这个数据知道“哦~有两个地方依赖我的数据,我变化的时候需要通知它们~”。

Vue 面试知识点总结

订阅者Dep

class Dep {
    constructor () {
        /* 用来存放Watcher对象的数组 */
        this.subs = [];
    }

    /* 在subs中添加一个Watcher对象 */
    addSub (sub) {
        this.subs.push(sub);
    }

    /* 通知所有Watcher对象更新视图 */
    notify () {
        this.subs.forEach((sub) => {
            sub.update();
        })
    }
}

订阅者对象含有两个方法,addSub用来收集watcher对象,notify用来通知watcher对象去更新视图。

观察者Watcher

class Watcher {
    constructor () {
        /* 在new一个Watcher对象时将该对象赋值给Dep.target,在get中会用到 */
        Dep.target = this;
    }

    /* 更新视图的方法 */
    update () {
        console.log("视图更新啦~");
    }
}

Dep.target = null;

观察者对象在实例化的时候就需要绑定它所属的Dep。同时还有一个update方法去更新视图。

依赖收集原理

function defineReactive (obj, key, val) {
    /* 一个Dep类对象 */
    const dep = new Dep();
    
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function reactiveGetter () {
            /* 将Dep.target(即当前的Watcher对象存入dep的subs中) */
            dep.addSub(Dep.target);
            return val;         
        },
        set: function reactiveSetter (newVal) {
            if (newVal === val) return;
            /* 在set的时候触发dep的notify来通知所有的Watcher对象更新视图 */
            dep.notify();
        }
    });
}

class Vue {
    constructor(options) {
        this._data = options.data;
        observer(this._data);
        /* 新建一个Watcher观察者对象,这时候Dep.target会指向这个Watcher对象*/
        // 实例化一个观察者
        new Watcher();
        /* 在这里模拟render的过程,为了触发test属性的get函数 */
        console.log('render~', this._data.test);
        // 触发get之后,会将上面刚实例化的watcher对象,添加到Dep对象中。
        
        // 注:这里只实例化了一个watcher,其实watcher对象没有我们上诉的那么简单,它记录的是当前引用的相关信息。为方便下次数据的更新时候,去更新视图
    }
}

当触发一个属性的get方法后,会执行我们的依赖收集。首先实例化一个watcher对象,这个watcher对象有这个属性的更新视图的方法。然后通过Dep的addSub方法将该watcher对象添加到Dep订阅者中。

【依赖收集】的关键条件:(1)触发get方法 (2)新建一个watcher对象

总结: 到了这里我们已经吧响应式系统学了,主要是get进行依赖收集,set中用过watcher观察者去更新视图。


以上所述就是小编给大家介绍的《Vue 面试知识点总结》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Real-Time Rendering, Third Edition

Real-Time Rendering, Third Edition

Tomas Akenine-Moller、Eric Haines、Naty Hoffman / A K Peters/CRC Press / 2008-7-25 / USD 102.95

Thoroughly revised, this third edition focuses on modern techniques used to generate synthetic three-dimensional images in a fraction of a second. With the advent or programmable shaders, a wide varie......一起来看看 《Real-Time Rendering, Third Edition》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具