1.Object.defineProperty(obj,key,desc);
用法:1.给对象新增属性和特性
2.修改对象属性值和特性
desc(属性特性):
1.enumerable:boolean 可枚举
2.writable :boolean 可写
3.value:any 赋值
4.get 取值
5.set 改值
2.思路:
对象的赋值和改值其实是通过Object.defineProperty的get和set特性来实现的,一般默认模式。
通过改写属性的get和set的特性,来实现对一个对象的监听。
3.举例:
var obj = {age:23}; console.log(obj.age); //23 Object.defineProperty(obj,'age',{ get(){ return 24; } }); console.log(obj.age); //24 obj.age = 25; console.log(obj.age); //24
原理:对象属性和赋值取值都会触发自身的get和set特性。
4.实现:
/*js 监听器*/ var transi = ""; function observe(obj,key){ if(obj[key] && (typeof obj[key] == 'object')){ Object.keys(obj[key]).forEach((v,index)=>{ observe(obj[key],v,obj[key][v]); }); } else { Object.defineProperty(obj,key,{ set(newV){ transi = newV; console.log('值改变'); }, get(){ console.log('新值为' + transi); return transi; } }) } } var obj = {name : 'wang',age:{max:12,good:{at:30}}}; observe(window,'obj'); obj.age.good.at = 44; console.log(obj.age.good.at);
5.延伸:
vue的双向绑定机制:当改变一个值时,在这个值的set特性中触发其他值的改变,实现数据实时更新的机制。
6.核心:
1.observer观察者: 观察一个对象,当某一属性改变时,触发set特性,由set触发与之关联的属性,哪些与之关联,怎么建立起关系?需要一个订阅者,即为一个数组,存放一些关联的对象。
2.watcher订阅者: 订阅者需要自己的更新机制,在set中被触发时需要及时更新自己的数据,再渲染到页面上,需要complier来解析页面,实现view层改变。
3.complier解析: 通过js获取指令模板,正则匹配换值,将操作封装放进set函数中实现view层自动更新。
7.数组的push、shift、concat、unshift、pop等api触发数据更新重新渲染:
数组没法像对象可以对字段的监听,若想实现监听,必然需要重写push、shift、concat、unshift、pop这些函数
方案一:
const push1 = Array.prototype.push; Array.prototype.push = function () { render(); //拦截进行数组render重新渲染 return push1.apply(this,arguments); };
此方案虽然实现数组的监听,但也改变了所有数组的原型,而且不是所有数组都需要监听;
方案二:
中心思想:代理原型
var obj = Object.create(Array.prototype);
var prototypePush = Array.prototype.push;
obj.push=function () {
render(); //拦截进行数组render重新渲染
return prototypePush.apply(this,arguments);
};
var arr = [];
arr.__proto__ = obj;