对象是无序属性的集合,而这些属性在建立是都带有一些特征值(能够理解为属性的属性,天生自带的),这些特征值是为了实现JavaScript引擎用的,所以JavaScript不能直接访问。vue
JavaScript经过这些特征值来定义属性的行为(属性是否删除,枚举,修改等)。数组
例如,在全局定义的属性是会挂载到window上的。当想删除window上的这个属性,是不能够的。也就是说window上的属性是不可配置的。delete window.obj //false 函数
Function.prototype当你修改为其余值,其原始值并无改变。是不可写的。this
在好比,咱们的for in是能够枚举原型链上属性的,但全部的原型顶端都是Object.prototype.但for in 并无枚举出来。因此Object.prototype是不可枚举的。spa
属性分为两种类型:1数据属性 2访问器属性。例如:通常咱们本身在对象设置的属性默认是数据属性,而Window上的那么属性是访问器属性。prototype
怎样知道这个属性究竟是数据属性仍是访问器属性?code
使用Object.getOwnPropertyDescriptor(属性所在的对象,属性)方法。 返回一个对象,当时访问器属性时,该对象属性有enumerable,configurable,get,set。当时数据属性,该对象返回的属性有value,writable,enumerable,configurable.对象
var obj = {name:'zwq',age:18};
console.log(Object.getOwnPropertyDescriptor(obj,'name')); //name属性属性
//{value: "zwq", writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(window,'name')); //window上的name属性时访问器属性
//enumerable: true, configurable: true, get: ƒ, set: ƒ}
数据属性blog
普通定义的属性 默认值前三个都是true,最后一个是undefined。递归
当咱们想到修改属性默认的特性,使用Object.defineProperty(属性所在对象,属性的名字,描述符对象)方法。
当使用Object.defineProperty方法第二个参数属性的名字不存在时,该方法会建立这个属性,而且该属性的特性除了value剩下的特性的默认值都是false。也就是说当你想让这个用Object.defineProperty方法建立的属性跟正常的属性同样可枚举,配置,写入,必须把这个属性值的特性都改成true。不然就是false。
var obj = {name:'zwq',age:18};
Object.defineProperty(obj,'name',{ 修改name属性的特性,值为haha,而且name属性不能修改值
value:'haha',
writable:false //默认值是true,改成false,不可写。
})
Object.defineProperty(obj,'sex',{建立一个sex属性,这个属性不可枚举
value:'woman',
writable:true,
configurable:true,
})
访问器属性
访问器属性不包含writable和value,他包含的是一对getter和setter函数,在读取访问器属性是,会调用getter函数,并返回有效的值,在写入访问器属性时(修改属性)会调用setter函数并传入新值。访问器包含4个特性
定义访问器属性,一样也必须商用Object.defineProperty().
function Person(){
this._name = 'zwq',
this.age = 18
}
var person = new Person();
Object.defineProperty(person,'name',{
set(newValue){
console.log('set');
this._name = newValue //设置或修改属性时,会调用set函数,把设置的值经过参数传进去后,用一个变量或属性保存。而且当调用get,return就是返回的这个值
},
get(){
return this._name; //当读取属性时 返回return的值
}
})
不必定非要同时指定getter和setter,只指定getter意味着属性是不能写。
vue的双向数据劫持绑定(主要应用于表单中)的原理就是利用Object.defineProperty来检测数据的变化。
双向劫持绑定时当视图(页面的某一元素)发生改变时,数据跟着改变,当数据改变时,视图也跟着改变。例以下面的输入框里面的内容改变时,数据(对象或数组)改变。检测数据改变。底下的div文本根据数据的改变而改变。
上面咱们介绍到,当数据改变时会触发set方法。由此咱们就能够检测数据的变化。<input type="text" id="Oinput"><div id="view"></div>
var input = document.getElementById('Oinput'); var view = document.getElementById('view'); var data = { valueObj :{ value:'zwq' } } //当输入框数据发生改变时,数据跟着改变 input.oninput = function(){ data.valueObj.value = this.value; } // 更新视图 function upData(){ view.innerText = data.valueObj.value; } upData(data); obServe(data); // 监控某个对象是否发生改变 function obServe(data){ //判断当前传的是不是对象,若是不是,直接return if(!data || !(data instanceof Object)){return data} //获取全部属性名。使用keys方法能够获取全部属性名(包括原型上的)并保存带数组中 var arrProperty = Object.keys(data); //遍历数组,调用defindRective检测每个属性值的改变 arrProperty.forEach(function(key){ defindRective(data,key,data[key]); //传入3个参数,当前对象,当前属性,当前属性值 }) } function defindRective(obj,key,val){ obServe(val); //使用递归,当想上面的数组,对象套对象的形式,因为里面的对象是一个引用值,没法检测里面的数据变化,因此使用递归。 Object.defineProperty(obj,key,{ //核心:使用Object,definPropert的set检测数据的改变。 set(newValue){ console.log(5); if(newValue == val) return val; val = newValue; upData(); //当数据变化,跟新视图 }, get(){ return val; } }) }