js知识梳理1:理解对象的属性特性
写在前面
注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:javascript高级程序设计第三版和javascript权威指南第六版,感谢它们的作者和译者。有发现什么问题的,欢迎留言指出。
1.数据属性
数据属性的4个特性:
- 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个参数:对象,属性名字和描述符对象。
//修改属性默认特性: 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之后就会有限制了:
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个属性特性如下:
- configurable:①表示能否通过delete删除属性从而重新定义,②能否修改属性的特性,③能否把属性修改为数据属性。对象直接量的默认值true
- enumerable:表示能否通过for-in循环返回属性。对象直接量的默认值true
- get:在读取属性时调用的函数。对象直接量默认值undefined
- set:在写入属性时调用的函数。对象直接量的默认值undefined
定义存储器属性最简单的方法是使用对象直接量语法的拓展写法:
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()方法定义存储器属性:
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修改为存储器属性,可以监听到数据的变化。
3.定义多个属性
经常要创建或修改多个属性,这时候可以使用object.defineproperties()方法,它接收2个参数,要添加或修改属性的对象和一个映射表,包含名称和属性描述符。
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。
- 如果数据属性是不可配置且不可写的,则不能修改它的值。然而可配置但不可写属性的值是可以修改的(做法:先将它标记为可写的,然后修改它的值,最后转换为不可写的)。
上一篇: tp5多入口配置
下一篇: Core Java(一)
推荐阅读
-
js知识梳理1:理解对象的属性特性
-
对xmlHttp对象方法和属性的理解_基础知识
-
对xmlHttp对象方法和属性的理解_基础知识
-
js: 对象中单个属性的特性
-
闭包及访问量属性和类与对象解构赋值以及js中对html中的dom操作(时间有点紧,没全理解透,需回头整理)
-
html文档中的location对象属性理解及常见的用法_基础知识
-
使用js,根据数组中对象属性值的不同将数组进行分组-1
-
html文档中的location对象属性理解及常见的用法_基础知识
-
闭包及访问量属性和类与对象解构赋值以及js中对html中的dom操作(时间有点紧,没全理解透,需回头整理)
-
深入理解JS正则表达式之REGEXP对象属性的解析