原型模式
红宝书147页 (以下实例均摘抄自红宝书,不全,实例可直接翻书)
- 一图说明一切:

- 所有的构造函数都会有一个prototype属性(无需定义),指向该构造函数的原型对象(prototype是指针不是对象!)
- 所有原型对象都会有一个constructor属性(无需定义),指向其对应的构造函数(constructor是指针不是对象!)
- 构造函数生成的实例都会有一个_proto_属性(无需定义,对开发者不可见),指向构造函数的原型对象
相关函数
- 无法访问_proto_,但可以通过isPrototypeOf()确定对象与原型对象的关系:
Person.prototype.isPrototypeOf(person1) //true
- Object.getPrototypeOf(),可以返回_proto_的值:
Object.getPrototypeOf(person1) == Person.prototype //true
同名覆盖
-
当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性,但不会修改那个属性。使用delete操作符可以完全删除实例属性,但不能删除原型属性及变量
-
hasOwnProperty()可以检测一个属性是存在于实例还是存在于原型。只有当给定属性存在于对象实例中,才会返回true:
person1.hasOwnProperty("name")
- Object.getOwnPropertyDescriptor() 用于获取实例属性的描述符,如果要取得原型属性的描述符,必须在原型对象上调用Object.getOwnPropertyDescriptor(该实例摘自MDN,无原型对象的例子):
var o, d;
o = { get foo() { return 17; } };
d = Object.getOwnPropertyDescriptor(o, "foo");
// d {
// configurable: true,
// enumerable: true,
// get: /*the getter function*/,
// set: undefined
// }
o = { bar: 42 };
d = Object.getOwnPropertyDescriptor(o, "bar");
// d {
// configurable: true,
// enumerable: true,
// value: 42,
// writable: true
// }
o = {};
Object.defineProperty(o, "baz", {
value: 8675309,
writable: false,
enumerable: false
});
d = Object.getOwnPropertyDescriptor(o, "baz");
// d {
// value: 8675309,
// writable: false,
// enumerable: false,
// configurable: false
// }
原型与in操作符
- in操作符的使用:单独使用和for-in循环中使用
- 单独使用:in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中
function Person(){}
Person.prototype.name = "li"
var person1 = new Person();
alert("name" in person1) //true
- object.hasOwnProperty()可判断属性是否在实例上,与in结合使用,可以写出判断属性是否在原型上的函数:
function hasPrototypeProperty(object, name){
return !object.hasOwnProperty(name) && (name in object);
}
- for-in循环,返回的是所有能够通过对象访问的、可枚举的(enumerated)属性,其中既包括存在于实例中的属性,也包括存在于原型中的属性。如果有实例属性屏蔽了原型属性,且该原型属性为不可枚举的,该实力属性也会在for-in循环中返回。
-
正常情况下,开发人员直接定义的属性都是可枚举的
-
要取得对象上所有可枚举的实例属性,可以使用Object.keys()方法,其返回一个包含所有可枚举属性的字符串数组


- 如果想要得到所有实例属性,无论它是否可枚举,都可以使用Object.getOwnPropertyNames()方法
var keys = Object.getOwnPropertyNames(Person.prototype);
alert(keys);//"constructor,name,age"
更简单的原型语法
- 直接用对象字面量形式创建新对象:
Person.prototype = {
name:"li",
age: 29
}
- 但是这样等同于完全重写了prototype对象,因此constructor属性也就变成了新对象的constrctir属性(指向Object构造函数),不再指向Person函数。所以,可以专门写个constructor:
Person.prototype = {
constructor : Person,
...
}
- 这种方法重设的constructor属性会导致其Enumerable特性被设置为true,默认情况下,原生的constructor属性是不可枚举的。可以使用Object.defineProperty():
Object.defineProperty(Person.prototype, "constructor", {
enumrable:false,
value:Person
})
原型的动态性
- 正常情况下,给原型定义属性或方法,会在实例上实时展现;但是如果重写了原型,实例中的指针不会指向重写的原型
function Person(){}
var friend = new Person();
Person.prototype = {
constructor:Person,
name:"li"
}
friend.name //undefined