上节我们讨论了对象的定义和对象的创建,知道了函数也是对象,知道了对象都是由函数创建的,知道了对象的原型和函数的原型属性的关系。这节说一下关于对象属性的操作,下节就可以切入正题了。
属性删除
1 var person = {age : 28, title : 'fe'}; 2 delete person.age; // true 3 delete person['title']; // true 4 person.age; // undefined 5 delete person.age; // true 6 7 delete Object.prototype; // false, 8 9 var descriptor = Object.getOwnPropertyDescriptor(Object, 'prototype'); 10 console.log(descriptor) //Object {value: Object, writable: false, enumerable: false, configurable: false}
delete操作符删除一个属性值后会返回true,第5行也返回true是因为person.age已经是个undefined,所以仍然会返回一个true,第7行删除Object的prototype属性返回了一个false,我们可以通过第9行Object.getOwnPropertyDescriptor()方法查看一下Object.prototype的特性,configurable属性值为false(不可配置),因此返回false。
属性检测
1 var cat = new Object(); 2 cat.legs=4; 3 'legs' in cat; //true 4 'toString' in cat; //false 5 cat.propertyIsEnumerable('legs'); // true 6 cat.propertyIsEnumerable('toString'); // false
使用propertyIsEnumerable()可以判断一个属性是不是可枚举的,如果想设置一个属性的特性是不是可枚举的怎么办呢,看下边:
1 Object.defineProperty(cat, 'price', {enumerable : true, value : 1000}); 2 cat.propertyIsEnumerable('price'); // true 3 cat.hasOwnProperty('price'); // true
使用Object.defineProperty()方法可以设置属性的特性值,如上我们可以把可枚举的特性设置为true或false。
属性枚举
in关键字可以判断属性是否存在,for in语句则不能枚举enumerable 值为false的属性,如:
1 var o={a:'1',b:'2'} 2 Object.defineProperty(o,'c',{ 3 Enumberable:false 4 }); 5 console.log('c' in o) //true 6 var key; 7 for(key in o){ 8 console.log(key) //a,b 9 }
get/set方法
get/set方法是另一种进行属性操作的方式,如:
1 var man = { 2 name : 'James', 3 get age() { 4 return new Date().getFullYear() - 1988; 5 }, 6 set age(val) { 7 console.log('Age can\'t be set to ' + val); 8 } 9 } 10 console.log(man.age); // 27 11 man.age = 100; // Age can't be set to 100 12 console.log(man.age); // 27
取一个属性值age时会触发get方法,给age赋值时触发set方法,赋值成不成功取决于set方法内部是否会对属性进行修改。
属性标签
1 Object.getOwnPropertyDescriptor({pro : true}, 'pro'); 2 // Object {value: true, writable: true, enumerable: true, configurable: true} 3 Object.getOwnPropertyDescriptor({pro : true}, 'a'); // undefined
前边提到过这个方法,可以返回一个属性特性描述的对象,分别有4个属性,value表示属性值,writable表示属性值是否可写,enumberable表示属性值是否可被枚举,configurable表示属性是否可被用其他方式进行操作(如delete操作符)。
1 Object.defineProperties(person, { 2 title : {value : 'fe', enumerable : true}, 3 corp : {value : 'BABA', enumerable : true}, 4 salary : {value : 50000, enumerable : true, writable : true}, 5 luck : { 6 get : function() { 7 return Math.random() > 0.5 ? 'good' : 'bad'; 8 } 9 }, 10 promote : { 11 set : function (level) { 12 this.salary *= 1 + level * 0.1; 13 } 14 } 15 }); 16 17 Object.getOwnPropertyDescriptor(person, 'salary'); 18 // Object {value: 50000, writable: true, enumerable: true, configurable: false} 19 Object.getOwnPropertyDescriptor(person, 'corp'); 20 // Object {value: "BABA", writable: false, enumerable: true, configurable: false} 21 person.salary; // 50000 22 person.promote = 2; 23 person.salary; // 60000
使用Object.defineProperties()方法可以定义多个属性的值,而且get,set方法可以不针对同一个属性进行操作,这个例子可以系统包含整个知识点。所有的属性特性值不输入均默认为false。
下图提供了configurable和writable不同情况下的操作影响:
可以看出这两个属性值均为true时我们基本可以做任何操作,属性都为false时我们都做不了,其他情况就不再赘述了。
对象标签
对象标签有三个:__proto__,__class__,__extensible__,__proto__下节讨论。
__class__属性无法直接访问,我们只能借助于Object.toString方法来简介访问到,如下:
1 var toString = Object.prototype.toString; 2 function getType(o){return toString.call(o).slice(8,-1);}; 3 4 toString.call(null); // "[object Null]" 5 getType(null); // "Null" 6 getType(undefined); // "Undefined" 7 getType(1); // "Number" 8 getType(new Number(1)); // "Number" 9 typeof new Number(1); // "object" 10 getType(true); // "Boolean" 11 getType(new Boolean(true)); // "Boolean"
__extensible__标签表示对象是否可扩展,即该对象是否可以继续添加属性,看下边代码:
1 var obj = {x : 1, y : 2}; 2 Object.isExtensible(obj); // true 3 Object.preventExtensions(obj); 4 Object.isExtensible(obj); // false 5 obj.z = 1; 6 obj.z; // undefined, add new property failed 7 Object.getOwnPropertyDescriptor(obj, 'x'); 8 // Object {value: 1, writable: true, enumerable: true, configurable: true} 9 10 Object.seal(obj); 11 Object.getOwnPropertyDescriptor(obj, 'x'); 12 // Object {value: 1, writable: true, enumerable: true, configurable: false} 13 Object.isSealed(obj); // true 14 15 Object.freeze(obj); 16 Object.getOwnPropertyDescriptor(obj, 'x'); 17 // Object {value: 1, writable: false, enumerable: true, configurable: false} 18 Object.isFrozen(obj); // true 19 20 // [caution] not affects prototype chain!!!
第2行代码使用Object.isExtensible()方法,我们可以检测是否可以进行对象属性扩展,然后Object.preventExtensions()方法,我们可以设置对象不能进行扩展,但该对象属性标签的原始值仍然保持不变,如第7行;
使用seal()方法会将该对象的所有属性标签的configurable值设置为false,而freeze()方法会将该对象的所有属性标签的configurable和writable值均设置为false。
下节开始讨论__proto__原型链和继承相关内容。