前言:
本文依照上一篇文章为基础进行书写,可先看上一篇开发环境的搭建后再来看本文章。链接:博客园
什么是响应式?
简单的来说就是更改数据的时候,视图也会更新。
vue是利用了Object.defineProperty的方法里面的setter 与getter方法的观察者模式来实现。
1.vue响应式原理
1.导出vue构造函数
import {initMixin} from './init';functionVue(options) {this._init(options);
}
initMixin(Vue);//给原型上新增_init方法
exportdefault Vue;
2.init方法中初始化vue状态
import {initState} from './state';
exportfunctioninitMixin(Vue){
Vue.prototype._init= function(options) {
const vm= this;
vm.$options=options//初始化状态
initState(vm)
}
}
根据不同属性进行初始化操作
export functioninitState(vm){
const opts=vm.$options;
// 判断里面有哪些数据,并进行初始化
// 如 props, data, methods, computed, watch...if(opts.props){
initProps(vm);
}if(opts.methods){
initMethod(vm);
}if(opts.data){//初始化data
initData(vm);
}if(opts.computed){
initComputed(vm);
}if(opts.watch){
initWatch(vm);
}
}functioninitProps(){}functioninitMethod(){}functioninitData(vm){
// 数据响应式原理
let data = vm.$options.data; // 用户传入的数据
// vm._data 就是检测后的数据了
data = vm._data = typeof data === 'function' ? data.call(vm) : data;
// 观测数据
observe(data); // 观测这个数据
}functioninitComputed(){}function initWatch(){}
3.初始化数据
import {observe} from './observer/index.js'
functioninitData(vm){
//用户传递过来data中的数据
let data=vm.$options.data;
//vm._data 就是监测后的数据
data= vm._data = typeof data === 'function' ?data.call(vm) : data;
// 观测数据
observe(data);
}
4.递归属性劫持
class Observer { //观测值
constructor(value){this.walk(value);
}
walk(data){//让对象上的所有属性依次进行观测
let keys =Object.keys(data);for(let i = 0; i < keys.length; i++){
let key=keys[i];
let value=data[key];
defineReactive(data,key,value);
}
}
}functiondefineReactive(data,key,value){
observe(value);
Object.defineProperty(data,key,{
get(){returnvalue
},
set(newValue){if(newValue == value) return;
observe(newValue);
value=newValue
}
})
}
exportfunctionobserve(data) {
// 判断data是不是对象,当null为空是也是返回object
if(typeof data !== 'object' && data != null){return;
}return newObserver(data);
}
上面通过打印可以查看到data中的属性都添加了get和set属性,实现更新
5.数组方法的劫持
import {arrayMethods} from './array';
class Observer {//观测值
constructor(value){
// 对数组索引进行拦截 性能差而且直接更改索引的方式并不多
Object.defineProperty(data,'__ob__',{ // __ob__ 是一个响应式饿表示 对象数组都有
enumerable:false, // 不可枚举
configurable:false,
value:this
})
// data.__ob__ = this; // 相当于在数据上可以获取到__ob__这个属性 指代的是Observer的实例
if(Array.isArray(data)){
// vue如何对数组进行处理呢? 数组用的是重写数组的方法 函数劫持
// 改变数组本身的方法我就可以监控到了
data.__proto__ = arrayMethods; // 通过原型链 向上查找的方式
// [{a:1}] => arr[0].a = 100
this.observeArray(data);
}else{
this.walk(data); // 可以对数据一步一步的处理
}
}
observeArray(value){for(let i = 0 ; i < value.length ;i ++){
observe(value[i]);
}
}
}
重写数组原型方法
let oldArrayProtoMethods =Array.prototype;
export let arrayMethods=Object.create(oldArrayProtoMethods);
let methods=['push','pop','shift','unshift','reverse','sort','splice'];
methods.forEach(method=>{
arrayMethods[method]= function(...args) {
const result= oldArrayProtoMethods[method].apply(this, args);
const ob= this.__ob__;
let inserted;switch(method) {case 'push':case 'unshift':
inserted=args;break;case 'splice':
inserted= args.slice(2)default:break;
}if (inserted) ob.observeArray(inserted); //对新增的每一项进行观测
returnresult
}
})
增加__obo__属性
class Observer {
constructor(value){
Object.defineProperty(value,'__ob__',{
enumerable:false,
configurable:false,
value:this});//...
}
}
给所有响应式数据增加标识,并且可以在响应式上获取Observer实例上的方法;
最后附上码云地址:链接
每天学习一点,记录一点...