构造函数、原型对象、实例对象之间的关系错综复杂,关于它们的属性和方法很多,长得也很像。这里归纳出来,方便记忆和查阅。
对象属性类型
数据属性
[[Configurable]]
:表示能否通过delete删除属性从而重新定义属性、能否修改属性的特性、能否把属性修改为访问器属性。默认值为true
。[[Enumerable]]
:表示是否可枚举。默认值为true
。[[Writable]]
:表示能否修改属性的值。默认值为true
。[[Value]]
:包含属性的数据值,在这里读写属性。默认值为undefined
。
修改属性的特性:Object.defineProperty()
、Object.defineProperties()
。调用这两个方法时,如果不指定,configurable
、enumerable
、writable
特性的默认值都是false
。
//定义一个属性
var person = {};
Object.defineProperty(person, 'name', {
value: 'hiyohoo',
configurable: true,
enumerable: true,
writable: true
});
//定义多个属性
var person = {};
Object.defineProperties(person, {
name: {
value: 'hiyohoo'
},
age: {
value: 24,
configurable: true,
writable: true
}
});
获取属性的特性:Object.getOwnPropertyDescriptor()
只能用于实例属性,要取得原型属性的描述符,需要在原型上使用该方法。
var descriptor = Object.getOwnPropertyDescriptor(person, 'age');
alert(descriptor.writable); //true
访问器属性
[[Configurable]]
[[Enumerable]]
[[Get]]
:读取属性时调用该函数。默认值为undefined
。[[Set]]
:写入属性时调用该函数。默认值为undefined
。
访问器属性不能直接定义,必须使用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;
}
}
});
book.year = 2016;
console.log(book.edition); //13
属性和方法
以下的属性和方法均以下面的代码为例:
var Person = function(name) {
this.name = name;
};
Person.prototype.school = 'HNU';
Person.prototype.sayName = function() {
return this.name;
};
var person = new Person('hiyohoo');
构造函数
prototype
指向原型对象,包含所有被实例共享的属性和方法。
console.log(Person.prototype); //Person{}
原型对象
constructor
指向构造函数。
console.log(Person.prototype.constructor === Person); //true
isPrototypeOf()
判断实例与原型之间的关系。
console.log(Person.prototype.isPrototypeOf(person)); //true
实例对象
constructor
沿着原型链找到原型中的constructor
属性,最终指向构造函数。
console.log(person.constructor === Person); //true
__proto__
Firefox、Safari、Chrome支持这个属性,指向原型对象。
console.log(person.__proto__ === Person.prototype); //true
hasOwnProperty()
从Object
中继承而来,判断属性是否是实例的私有属性,而不是继承而来的共享属性。
console.log(person.hasOwnProperty('name')); //true
console.log(person.hasOwnProperty('school')); //false
Object
Object.getPrototypeOf()
ECMAScript 5
中新增的方法,返回实例的原型。
console.log(Object.getPrototypeOf(person)); //Person{}
Object.keys()
ECMAScript 5
中新增的方法,返回一个包含所有可枚举实例属性的字符串数组。
console.log(Object.keys(person)); //["name"]
console.log(Object.keys(Person.prototype)); //["school", "sayName"]
Object.getOwnPropertyNames()
返回所有实例属性,无论是否可枚举。
console.log(Object.getOwnPropertyNames(person)); //["name"]
console.log(Object.getOwnPropertyNames(Person.prototype)); //["constructor", "school", "sayName"]
操作符
delete
删除一个configurable
为true
的私有属性。
delete person.name;
delete person.school;
console.log(person.name); //undefined
console.log(person.school); //HNU
for-in
返回所有能够访问到的属性。
for (p in person) {
console.log(p); //name school sayName
}
in
对象能够访问到属性时返回true
console.log('name' in person); //true
console.log('sayName' in person); //true
console.log('age' in person); //false
同时使用hasOwnProperty()
方法和in
操作符,可以确定一个属性是存在于对象中还是存在于原型中。
function isPrototypeProperty(object, name) {
if (!(name in object)) {
return ("Can't find " + '"' + name + '"');
} else if (object.hasOwnProperty(name)) {
return false;
} else {
return true;
}
}
console.log(isPrototypeProperty(person, 'name')); //false
console.log(isPrototypeProperty(person, 'school')); //true
console.log(isPrototypeProperty(person, 'age')); //Can't find "age"
instanceof
用于判断一个对象是否是某个对象的实例。
console.log(person instanceof Person); //true
console.log(person instanceof Object); //true
转载请注明出处:https://segmentfault.com/a/1190000004561741
文章不定期更新完善,如果能对你有一点点启发,我将不胜荣幸。