JavaScript

超轻量级php框架startmvc

Vue2.X和Vue3.0数据响应原理变化的区别

更新时间:2020-09-21 19:18:01 作者:startmvc
defineProperty定义对象的属性,只不过属性里的get和set实现了响应式。常用:value属性值getsetwr

defineProperty 定义对象的属性,只不过属性里的get和set实现了响应式。

常用:

  • value属性值
  • get
  • set
  • writeable 是否可写
  • enumrable 可遍历

Vue从改变一个数据到发生改变的过程

 Vue2.X数据响应原理

创建页面,实现延时2s修改对象的值。


<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <title>LearnVue3.0</title>
</head>
<body>
 <div id="app"></div>
 <script type="text/javascript" src="test.js"></script>
 <script type="text/javascript">
 const vm = new vue();
 setTimeout(function () {
 console.log('change');
 console.log(vm.$data);
 vm.$data.a = 444;
 }, 2000);

 </script>
</body>
</html>

defineProperty 实现:


function vue() {
 this.$data = {
 a: 1
 };
 this.el = document.getElementById('app');
 this._html = "";
 this.observe(this.$data);
 this.render();
}

vue.prototype.observe = function (obj) {
 let self = this;
 let value;

 for (let key in obj) {
 value = obj[key];
 if (typeof value === 'object') {
 this.observe(value);
 } else {
 Object.defineProperty(this.$data, key, {
 get: function () {
 return value;
 },
 set: function (newvalue) {
 value = newvalue;
 self.render()
 }
 })
 }
 }
}

vue.prototype.render = function () {
 this._html = "I am " + this.$data.a;
 this.el.innerHTML = this._html;
}

在Chrome中console运行,结果页面显示: I am 444

针对数组特性化处理:


let arraypro = Array.prototype;
// 为什么要create再次创建对象,create是深拷贝,不影响之前的arraypro
let arrayob = Object.create(arraypro);
// 定义哪些方法触发更新
let arr = ["push", "pop", "shift"];

// arr里的方法,既能保持原有方法,又能触发更新
// 装饰者模式
arr.forEach(function (method, index) {
 // 对自己的push方法重写
 arrayob[method] = function () {
 let ret = arraypro[method].apply(this, arguments);
 // self.render();
 console.log('检测到数组变化,触发更新');
 return ret;
 }
});

在Chrome中console运行示例:


let arr = [];
arr.__proto__ = arrayob;
arr.push(1);

结果显示:

 

Vue3.0数据响应原理

Vue3.0数据响应原理

创建页面,实现延时2s修改对象的值。代码同上。

Proxy实现:


function vue() {
 this.$data = {
 a: 1
 };
 this.el = document.getElementById('app');
 this._html = "";
 this.observe(this.$data);
 this.render();
}

vue.prototype.observe = function (obj) {
 let self = this;

 this.$data = new Proxy(this.$data, {
 get: function (target, key) {
 return target[key];
 },
 set: function (target, key, newvalue) {
 target[key] = newvalue;
 self.render();
 }
 })
}

vue.prototype.render = function () {
 this._html = "I am " + this.$data.a;
 this.el.innerHTML = this._html;
}

在Chrome中console运行,结果页面显示: I am 444

为什么改用Proxy

  • defineProperty只能监听某个属性,不能对全对象监听
  • 可以省去for in循环提升效率
  • 可以监听数组,不用再去单独的对数组做特异性操作

Proxy还能做什么

校验类型


function createValidator(target, validator) {
 return new Proxy(target, {
 _validator: validator,
 set(target, key, value, proxy) {
 if(target.hasOwnProperty(key)) {
 let validator = this._validator[key];
 if(validator(value)) {
 return Reflect.set(target, key, value, proxy);
 } else {
 throw Error('type error');
 }
 }
 }
 })
}

let personValidator = {
 name(val) {
 return typeof val === 'string';
 },
 age(val) {
 return typeof val === 'number' && val > 18;
 }
}

class person {
 constructor(name, age) {
 this.name = name;
 this.age = age;
 return createValidator(this, personValidator);
 }
}

在Chrome中console运行示例:


let tmp = new person('张三', 30);

结果显示:

真正的私有变量

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

Vue2.X 数据响应 Vue3.0数据响应