时间: 2019-10-19阅读: 97标签: 特性
从es5开始,js中开始拥有了一种描述属性特征的特性(即属性描述符)。根据特性的不同,可以把属性分成两种类型:数据属性和访问器属性。
对象是无序属性的集合,而这些属性在创建是都带有一些特征值(可以理解为属性的属性,天生自带的),这些特征值是为了实现JavaScript引擎用的,因此JavaScript不能直接访问。
先说说有哪些特性
JavaScript通过这些特征值来定义属性的行为(属性是否删除,枚举,修改等)。
为了方便后面的理解,有必要先说一下,有哪几个特性。
例如,在全局定义的属性是会挂载到window上的。当想删除window上的这个属性,是不可以的。也就是说window上的属性是不可配置的。delete window.obj //false
[[Configurable]] // true or false
Function.prototype当你修改成其他值,其原始值并没有改变。是不可写的。
[[Writable]] // true or false
在比如,我们的for in是可以枚举原型链上属性的,但所有的原型顶端都是Object.prototype.但for in 并没有枚举出来。所以Object.prototype是不可枚举的。
[[Enumerable]] // true or false
属性分为两种类型:1数据属性 2访问器属性。例如:一般我们自己在对象设置的属性默认是数据属性,而Window上的那么属性是访问器属性。
[[Value]] // everty thing
怎样知道这个属性到底是数据属性还是访问器属性?
[[set]] // function or undefined
使用Object.getOwnPropertyDescriptor(属性所在的对象,属性)方法。 返回一个对象,当时访问器属性时,该对象属性有enumerable,configurable,get,set。当时数据属性,该对象返回的属性有value,writable,enumerable,configurable.
[[get]] // function or undefined
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: ƒ}
纳尼,这些是什么鬼,不懂。
数据属性
先不要急,现在只需要知道有这几个特性,具体是什么意思,看到后面自然就懂了。
数据上行包含一个数据值的位置,可以读取和写入值,数据属性有4个描述其行为的属性,由于是这些值不能直接访问,是内部值,所以该规范把他们放在两对括号中。
谈define
属性是否可配置:[[Configurable]]:表能否通过delete删除属性,能够修改属性的特性,能否把属性修改为访问器属性属性是否可枚举:[[Enumerable]]:表能否通过for-in循环返回属性属性是否可修改:[[Writable]]属性的数据值 :[[value]]读取属性的时候,从这个位置读,写入属性的时候,把新值保存到这个位置。
数据属性和访问器属性都拥有特性,要想修改属性的特性,必须通过两个Object方法,即Object.defineProperty和Object.defineProperties。正如其字面意思,这两个方法都是用来定义(修改)属性的,前者一次只能定义一个属性,后者则可以多个。 不多说了,看API和例子吧
普通定义的属性 默认值前三个都是true,最后一个是undefined。
defineProperty(obj, prop, descriptor)
当我们想到修改属性默认的特性,使用Object.defineProperty(属性所在对象,属性的名字,描述符对象)方法。
obj: 将要被添加属性或修改属性的对象
当使用Object.defineProperty方法第二个参数属性的名字不存在时,该方法会创建这个属性,并且该属性的特性除了value剩下的特性的默认值都是false。也就是说当你想让这个用Object.defineProperty方法创建的属性跟正常的属性一样可枚举,配置,写入,必须把这个属性值的特性都改为true。否则就是false。
prop: 对象的属性
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,})
descriptor: 对象属性的特性
访问器属性
var person = {};
访问器属性不包含writable和value,他包含的是一对getter和setter函数,在读取访问器属性是,会调用getter函数,并返回有效的值,在写入访问器属性时(修改属性)会调用setter函数并传入新值。访问器包含4个特性
Object.defineProperty(person, birth, {
属性是否可配置:[[Configurable]]:表能否通过delete删除属性,能够修改属性的特性,能否把属性修改为访问器属性属性是否可枚举:[[Enumerable]]:表能否通过for-in循环返回属性[[Get]]:在读取属性时调用的函数。默认值是undefined。[[Set]]:在写入(或修改)属性时调用的函数。默认值undefined。
writable: false,
定义访问器属性,同样也必须商用Object.defineProperty().
value: 1995
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的值 } })
}); // 定义了一个不可写,值为1995的新属性
不一定非要同时指定getter和setter,只指定getter意味着属性是不能写。
注:在使用defineProperty方法定义新属性时(非修改旧属性),如果不指定,configurable, enumerable和writable特性的默认值都是false。所以,上面代码实际等同于:
vue的双向数据劫持绑定(主要应用于表单中)的原理就是利用Object.defineProperty来检测数据的变化。
var person = {};
双向劫持绑定时当视图(页面的某一元素)发生改变时,数据跟着改变,当数据改变时,视图也跟着改变。例如下面的输入框里面的内容改变时,数据(对象或数组)改变。检测数据改变。底下的div文本根据数据的改变而改变。
Object.defineProperty(person, birth, {
上面我们介绍到,当数据改变时会触发set方法。由此我们就可以检测数据的变化。
configurable: false,
input type="text"div /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; } })}
enumerable: false,
**
writable: false,
value: 1995
});
defineProperties(obj, props)
obj: 将要被添加属性或修改属性的对象
props: 该对象的一个或多个键值对定义了将要为对象添加或修改的属性的具体配置
var person = {}; Object.defineProperties(person, { birth: { value: 1995 }, age: { value: 21, writable: true } }); // 基本同Object.defineProperty,一单一复
数据属性
数据属性包含一个数值的位置,在这个位置可以读取和写入值。数据属性拥有4个特性
[[Configurable]]10bet,: 表示能否通过delete删除属性,能否修改属性的特性,能否把属性改为访问器属性。默认值: true
[[Enumerable]]: 表示能否通过for-in,Object.keys()迭代。默认值:true
[[Writable]]: 表示能否修改属性的值。默认值: true
[[Value]]: 表示属性的数据值。默认值: undefined
访问器属性
访问器属性不包含数据值,它们包含一对getter和setter函数。 在读取访问器属性时,会调用getter函数(即.操作符);在写入访问器属性时,会调用setter函数并传入新值(即=操作);访问器属性不能直接定义,需要使用后面提到的Object.defineProperty函数定义。访问器属性也拥有4个特性
[[Configurable]]: 同数据属性
[[Enumerable]]: 同数据属性
本文由10bet发布于Web前端,转载请注明出处:Js对象属性的特性 和defineProperty方法10bet
关键词: