js知识梳理1:理解对象的属性特性

1.数据属性

数据属性的4个特性:javascript

  • Configurable:①表示可否经过delete删除属性从而从新定义,②可否修改属性的特性,③可否把属性修改成访问器属性。对象直接量里默认值true。
  • Enumerable:表示可否经过for-in循环返回属性。对象直接量里默认值true。
  • Writable:表示可否修改属性的值。对象直接量里默认值true。
  • Value:包含这个属性的数据值。对象直接量里默认值undefined。
//查看对象直接量的属性的属性特性默认值 var people = {  name:'jaychou',  sayName:function () { console.log(this.name); } }; /**{value: "jaychou", writable: true, enumerable: true, configurable: true}*/ console.log(Object.getOwnPropertyDescriptor(people,'name')); /**{value: ƒ, writable: true, enumerable: true, configurable: true}*/ console.log(Object.getOwnPropertyDescriptor(people,'sayName')); //getOwnPropertyDescriptor对于继承属性和不存在的属性,返回undefined

要修改属性默认的特性,使用Object.defineProperty()方法,接收3个参数:对象,属性名字和描述符对象。java

//修改属性默认特性: Object.defineProperty(person,'job',{ emumerable:false,//不可枚举 value:'singer', writable:false,//不可写 configurable:true }); /**{name: "jaychou", sayName: ƒ, job: "singer"}*/ console.log(person); for(var prop in person){ //打印name,sayName console.log(prop); } //会报错 try{ person.job = 'director'; }catch (e) { //Cannot assign to read only property 'job' of object console.log(e); }

能够屡次调用Object.defineProperty()方法修改同一个属性,但在把configurable特性设置为false以后就会有限制了:markdown

Object.defineProperty(person,'height',{ configurable:false,//不可配置 writable:true, value:172 }); try{ Object.defineProperty(person,'height',{ configurable:true,//出错 enumerable:true,//出错 value:175,//正常 writable:false,//writable从true变false能够,false变true也会出错 }); }catch (e) { //Cannot redefine property: height at Function.defineProperty console.log(e); } try{ delete person.height; }catch (e) { //设置成不可配置后也不可删除:Cannot delete property 'height' of #<Object> console.log(e); }

另外,调用 Object.defineProperty()方法时,若是不指定,configurable、enumerable 和 writable 特性的默认值都是 false。若是是修改已有属性,则无此限制。函数

2.存储器属性

存储器属性不包含数据值,只包含包含 getter 和 setter 函数(非必需)。 在读取存储器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入存储器属性时,会调用 setter 函数并传入新值,这个函数负责决定如何处理数据。4个属性特性以下:post

  • Configurable:①表示可否经过delete删除属性从而从新定义,②可否修改属性的特性,③可否把属性修改成数据属性。对象直接量的默认值true
  • Enumerable:表示可否经过for-in循环返回属性。对象直接量的默认值true
  • Get:在读取属性时调用的函数。对象直接量默认值undefined
  • Set:在写入属性时调用的函数。对象直接量的默认值undefined

定义存储器属性最简单的方法是使用对象直接量语法的拓展写法:ui

var p = { x:3.0, y:4.0, //r是可读写的存取器属性 get r(){return Math.sqrt(this.x*this.x+this.y*this.y);}, set r(newValue){ var oldvalue = Math.sqrt(this.x*this.x+this.y*this.y); var ratio = newValue/oldvalue; this.x *= ratio; this.y *= ratio; }, //theta是只读存取器属性 get theta(){return Math.atan2(this.y,this.x);} } console.log(p.r); p.r = 25;

使用Object.defineProperty()方法定义存储器属性:this

var book = { _year:2004, edition:1 }; Object.defineProperty(book,"year",{ get:function () { return this._year; }, set:function (newValue) { if(newValue>2004){ this._year = newValue; this.edition += newValue - 2004; } } }) /**{get: ƒ, set: ƒ, enumerable: false, configurable: false}*/ console.log(Object.getOwnPropertyDescriptor(book,'year'));

如例子所示,使用存储器属性的常见方式,即设置一个属性的值会致使其余属性发生变化。还有一种常见就是如今流行的相似于Vue的响应式原理,就是把data中的属性都使用defineProperty修改成存储器属性,能够监听到数据的变化。spa

3.定义多个属性

常常要建立或修改多个属性,这时候可使用Object.defineProperties()方法,它接收2个参数,要添加或修改属性的对象和一个映射表,包含名称和属性描述符。code

var book1 = {}; Object.defineProperties(book1,{ _year:{ value:'2008' }, editor:{ enumerable:true, value:'2' }, year:{ get:function () { return this._year; }, set:function (newValue) { this._year = newValue; this.edition += newValue - 2004; } } });

4.对象的可扩展性

对象的可拓展性表示是否能够给对象添加新属性。全部内置对象和自定义对象都是显式可扩展的,宿主对象的可扩展性是由Javascript引擎定义的。对象

1.查询对象可拓展性
var teacher = {age:25}; //true:表明可拓展 console.log(Object.isExtensible(teacher));
2.转换为不可拓展(“锁定对象”)
Object.preventExtensions(teacher); //false console.log(Object.isExtensible(teacher)); try{ teacher.subject = 'math'; }catch (e) { //TypeError: Cannot add property subject, object is not extensible console.log(e); }

转换成不可拓展的操做是不可逆的,并且只能影响到对象自己的可拓展性,若是给一个不可拓展对象的原型添加属性,这个不可拓展对象一样会继承这些新属性。

5.密封对象

密封对象比锁定对象更高一层,除了不可拓展之外,对象的全部自身属性都设置成了不可配置的。一样密封对象操做是不可逆的。

var tea1 = {subject:'math'}; //false:表明未密封 console.log(Object.isSealed(tea1)); Object.seal(tea1); try{ Object.defineProperty(tea1,'subject',{ //enumerable:false,//出错 //configurable:true,//出错 writable:false//和上面说的同样,writable从true变成false能够,false变成true则出错 }); }catch (e) { console.log('出错..'); console.log(e); } //true:已密封 console.log(Object.isSealed(tea1));

6.冻结对象

冻结比密封对象多的效果是:能够将它自有的全部数据属性设置为只读(若是对象的存取器属性具备setter方法,存取器属性将不受影响,仍能够经过给属性赋值调用它们)。

var tea2 = {subject:'Chinese'}; //false:表明未冻结 console.log(Object.isFrozen(tea2)); Object.freeze(tea2); try{ tea2.subject = 'math'; }catch (e) { //TypeError: Cannot assign to read only property 'subject' of object console.log(e); } //true:已冻结 console.log(Object.isFrozen(tea2));

7.属性特性规则总结

  • 若是对象是不可拓展的,则能够编辑已有的自有属性,但不能给它添加新属性。
  • 若是属性是不可配置的,则不能修改它的可配置性和可枚举性。
  • 若是存取器属性是不可配置的,则不能修改其getter和setter方法,也不能将它转换为数据属性。
  • 若是数据属性是不可配置的,则不能将它转换为存取器属性。
  • 若是数据属性是不可配置的,则不能将它的可写性从false修改成true,但能够从true修改成false。
  • 若是数据属性是不可配置且不可写的,则不能修改它的值。然而可配置但不可写属性的值是能够修改的(作法:先将它标记为可写的,而后修改它的值,最后转换为不可写的)。
相关文章
相关标签/搜索