如[[Configurable]] 被兩對兒中括號 括起來的表示 不可直接訪問他們vue
修改屬性類型:使用Object.defineProperty() //IE9+ 和標準瀏覽器 支持node
查看屬性的數據特性:Object.getOwnPropertyDescriptor()es6
上圖輸出的就是瀏覽器
屬性類型分爲兩種:數據屬性和訪問器屬性。app
數據屬性:有四個dom
[[Configurable]]:表示可否經過delete刪除屬性,可否修改屬性特性、可否修改訪問器屬性 若是修改爲false 就不能在修改回來而且再次使用Object.defineProperty()修改屬性特性只能修改[[writable]] 默認true函數
[[Enumerable]]:表示可否表示目標屬性是否可遍歷 默認truethis
for in、Object.keys 和 JSON.stringify()不能返回屬性spa
[[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:'樹下的老大爺的博客' } });