在看JS构造函数、原型、原型链、继承相关内容时对对象的属性,比如[[Prototype]], constructor, prototype有些云里雾里,因为画原型链时,使用的是对象的自身属性(own property),但实际使用时,对象中又能继承原型属性(prototype property)。
还有些特点会让自己更加迷惑,比如“JS高程”提到任何对象都有constructor属性,但实际这里的constructor属性实际是原型属性。
学习当中如果能通过代码验证,印象会更加深刻,所以这篇文章记录下怎么获取对象的四种属性:自身可枚举属性,自身所有属性(可枚举+不可枚举),自身+原型可枚举属性,自身+原型所有属性(可枚举+不可枚举),以便在学习当中加以验证。
关于constructor属性为什么定义在原型中,可以参考这个问答JavaScript inheritance and the constructor property
自身可枚举属性
ES5+
如果支持ES5+的浏览器(即IE8以上),可以通过JS内建方法:
语法:
举例:
| var Person = function (name) {this.name = name;
 };
 
 
 Person.prototype.age = 26;
 
 
 var person = new Person('xiaog');
 
 
 Object.defineProperty(person, 'job', {
 value: 'FEDer',
 enumerable: false,
 configurable: true,
 writable: true,
 });
 
 
 Object.keys(person);
 
 | 
题外话:如果使用Object.defineProperty()方法,如果省略指明configurable等属性值,默认为false。
ES3+
如果需要兼容IE8及以下浏览器,可使用for...in。
for...in是默认枚举自身及原型中继承来的所有可枚举属性,下面讲完“自身/原型可枚举属性”再看怎么通过for...in来枚举“自身可枚举属性”
自身+原型可枚举属性
如上所述,通过for..in实现:   
语法:   
| for (property in object) { ...}
 
 | 
举例:   
| var Person = function (name) {this.name = name;
 };
 
 
 Person.prototype.age = 26;
 
 
 var person = new Person('xiaog');
 
 
 Object.defineProperty(person, 'job', {
 value: 'FEDer',
 enumerable: false,
 configurable: true,
 writable: true,
 });
 
 var person = new Person('xiaog');
 for (p in person) {
 
 console.log(p);
 }
 
 | 
Object.hasOwnProperty()
结合Object.hasOwnProperty()方法可以通过for...in实现对自身可枚举属性的遍历:
| var Person = function (name) {this.name = name;
 };
 
 
 Person.prototype.age = 26;
 
 
 var person = new Person('xiaog');
 
 
 Object.defineProperty(person, 'job', {
 value: 'FEDer',
 enumerable: false,
 configurable: true,
 writable: true,
 });
 
 for (p in person) {
 
 if (Object.hasOwnProperty(p)) {
 console.log(p);
 }
 }
 
 | 
自身所有属性
通过JS内建方法即可实现:
语法:
| Object.getOwnPropertyNames(obj);
 | 
举例:
| var Person = function (name) {this.name = name;
 };
 
 
 Person.prototype.age = 26;
 
 
 var person = new Person('xiaog');
 
 
 Object.defineProperty(person, 'job', {
 value: 'FEDer',
 enumerable: false,
 configurable: true,
 writable: true,
 });
 
 var ownAllProperties = Object.getOwnPropertyNames(person);
 
 
 console.log(ownAllProperties);
 
 | 
自身+原型所有属性
想要获取自身+原型所有属性没有内建的JS方法,可通过下面代码实现:
| function getAllPropertyNames( obj ) {
 var props = [];
 
 do {
 Object.getOwnPropertyNames( obj ).forEach(function ( prop ) {
 if ( props.indexOf( prop ) === -1 ) {
 props.push( prop );
 }
 });
 } while ( obj = Object.getPrototypeOf( obj ) );
 
 return props;
 }
 
 
 var Person = function (name) {
 this.name = name;
 };
 
 
 Person.prototype.age = 26;
 
 
 var person = new Person('xiaog');
 
 
 Object.defineProperty(person, 'job', {
 value: 'FEDer',
 enumerable: false,
 configurable: true,
 writable: true,
 });
 
 var allPropertiesNames = getAllPropertyNames(person);
 console.log(allPropertiesNames);
 
 | 
方法getAllPropertyNames可以简化成下面的代码:   
| function getAllPropertyNames( obj ) {var props = [];
 
 do {
 props= props.concat(Object.getOwnPropertyNames( obj ));
 } while ( obj = Object.getPrototypeOf( obj ) );
 
 return props;
 }
 
 | 
参考资料
【1】MDN for…in
【2】How to get all properties values of a Javascript Object (without knowing the keys)?
【3】How do I access properties of a javascript object if I don’t know the names?
【4】Is it possible to get the non-enumerable inherited property names of an object?
【5】JavaScript inheritance and the constructor property