红宝书总结-原型模式

487 阅读3分钟

原型模式

红宝书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循环中使用
  1. 单独使用: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);
}
  1. 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