如[[Configurable]] 被两对儿中括号 括起来的表示 不可直接访问他们
修改属性类型:使用Object.defineProperty() //IE9+ 和标准浏览器 支持
查看属性的数据特性:Object.getOwnPropertyDescriptor()
上图输出的就是
属性类型分为两种:数据属性和访问器属性。
数据属性:有四个
[[Configurable]]:表示能否通过delete删除属性,能否修改属性特性、能否修改访问器属性 如果修改成false 就不能在修改回来并且再次使用Object.defineProperty()修改属性特性只能修改[[writable]] 默认true
[[Enumerable]]:表示能否表示目标属性是否可遍历 默认true
Object.keys 和 JSON.stringify()也不能返回属性
[[writable]]:表示能否修改属性值 默认true
[[value]]:这个位置是属性值,属性值默认undefined 这就是你没有给值时候为什么默认undefined
访问器属性:
访问器属性:
[[get]]:获取属性值的时候触发get函数
[[set]]:设置属性值时触发set函数
VUE2.0的数据双向绑定就是使用的Object.defineProperty()重写set和get方法实现的,VUE3.0是使用es6中的proxy代理实现的了。
下面附赠VUE2.0的数据双向绑定原理(简易版因为这里没有虚拟dom层)
//发布者
class Vue{
constructor(options){
//new Vue时传进来的对象
this.options = options;
//对象下的data
this.$data = options.data;
//根据#el 获取到具体的dom元素
this.$el = document.querySelector(options.el);
//存放订阅者
this._directive={};
this.Observer(this.$data);
this.Compile(this.$el);
}
//劫持数据
Observer(data){
for(let key in data){
//_directive[inputText(key)] =[] []这里面存存储 订阅者
// 也就是都哪些dom元素使用inputText变量了
this._directive[key] = [];
//inputText(key)变量数据
let val = data[key];
//获取到订阅inputText(key)dom元素集合
let _obj = this._directive[key];
//defineproperty 核心方法
Object.defineProperty(this.$data,key,{
get:function () {
return val;
},
set:function(newVal){
//判断数据是否改动
if(val!==newVal){
val=newVal;
//便利订阅者 所有订阅者执行更新 也就是Watcher(下的update)
_obj.forEach(function (el) {
el.update();
})
}
}
})
}
}
//解析指令
Compile(el){
let nodes = el.children;
for (let i = 0; i<nodes.length;i++){
let node = nodes[i];
//判断当前元素下是否有 子元素
if(node.children.length){
//递归出所有#app下 dom元素
this.Compile(node);
}
//dom元素是否有v-text属性(指令)
if(node.hasAttribute('v-text')){
let attrValue = node.getAttribute('v-text');
//向订阅者容器 添加订阅者
this._directive[attrValue].push(new Watcher(node,this,attrValue,'innerHTML'));
}
if(node.hasAttribute('v-model')){
let attrValue = node.getAttribute('v-model');
//向订阅者容器 添加订阅者
this._directive[attrValue].push(new Watcher(node,this,attrValue,'value'));
let _this = this;
node.addEventListener('input',function () {
//vue实例下的data数据 赋值
_this.$data[attrValue] = this.value;
},false)
}
}
}
}
//订阅者
class Watcher{
constructor(el,vm,exp,attr){
//dom元素
this.el = el;
//vue实例对象
this.vm = vm;
//data下的变量名字
this.exp = exp;
//根据指令 怎样操作dom innerHTML等
this.attr =attr;
this.update();//初始化数据
}
update(){
//dom.(innerHTML等) = vue实例下的data[变量名]
this.el[this.attr] = this.vm.$data[this.exp];
}
}
//实例vue
var bb=new Vue({
el:'#app',
data:{
inputText:'树下的老大爷的博客'
}
});