vue手写响应式_Vue响应式原理(手写源码)

前言:

本文依照上一篇文章为基础进行书写,可先看上一篇开发环境的搭建后再来看本文章。链接:博客园

什么是响应式?

简单的来说就是更改数据的时候,视图也会更新。

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实例上的方法;

最后附上码云地址:链接

每天学习一点,记录一点...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值