构造函数、原型对象、实例对象之间的关系错综复杂,关于它们的属性和方法很多,长得也很像。这里归纳出来,方便记忆和查阅。

对象属性类型

数据属性

[[Configurable]]:表示能否通过delete删除属性从而重新定义属性、能否修改属性的特性、能否把属性修改为访问器属性。默认值为true
[[Enumerable]]:表示是否可枚举。默认值为true
[[Writable]]:表示能否修改属性的值。默认值为true
[[Value]]:包含属性的数据值,在这里读写属性。默认值为undefined

修改属性的特性:Object.defineProperty()Object.defineProperties()。调用这两个方法时,如果不指定,configurableenumerablewritable特性的默认值都是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删除一个configurabletrue的私有属性。

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

文章不定期更新完善,如果能对你有一点点启发,我将不胜荣幸。


hiYoHoo
2.2k 声望23 粉丝