注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:javascript高级程序设计第三版和javascript权威指南第六版,感谢它们的作者和译者。有发现什么问题的,欢迎留言指出。
数据属性的4个特性:
//查看对象直接量的属性的属性特性默认值 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。如果是修改已有属性,则无此限制。
存储器属性不包含数据值,只包含包含 getter 和 setter 函数(非必需)。 在读取存储器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入存储器属性时,会调用 setter 函数并传入新值,这个函数负责决定如何处理数据。4个属性特性如下:
定义存储器属性最简单的方法是使用对象直接量语法的拓展写法:
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修改为存储器属性,可以监听到数据的变化。
经常要创建或修改多个属性,这时候可以使用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; } } });
对象的可拓展性表示是否可以给对象添加新属性。所有内置对象和自定义对象都是显式可扩展的,宿主对象的可扩展性是由javascript引擎定义的。
var teacher = {age:25}; //true:代表可拓展 console.log(object.isextensible(teacher));
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); }
转换成不可拓展的操作是不可逆的,而且只能影响到对象本身的可拓展性,如果给一个不可拓展对象的原型添加属性,这个不可拓展对象同样会继承这些新属性。
密封对象比锁定对象更高一层,除了不可拓展以外,对象的所有自身属性都设置成了不可配置的。同样密封对象操作是不可逆的。
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));
冻结比密封对象多的效果是:可以将它自有的所有数据属性设置为只读(如果对象的存取器属性具有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));
如对本文有疑问, 点击进行留言回复!!
轻松解决 org.apache.taglibs.standard.tlv.JstlCoreTLV 困惑
vert实践五——Json?Protocol Buffer?FlatBuffers?
[基于tensorflow的人脸检测] 基于神经网络的人脸检测8——验证训练好的神经网络
selenium + ajax抓取英雄联盟全部英雄的详细信息及多线程保存全部皮肤图片到本地
网友评论