- 原型概念:每个函数都有一个 prototype (原型)属性,这个属性是一个指针,指向一个对象。
- 用途:让所有对象实例共享它所包含的属性和方法。
代码示例:
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas"
var person2 = new Person();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName); //true
1.理解原型对象
- 只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype 属性,这个属性指向函数的原型对象。
- 在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。
2.构造函数、原型、实例三者关系
Person.prototype.constructor == Person
【1】
isPrototypeOf() 判断原型对象是否是实例的原型
Person.prototype.isPrototypeOf(person1) // true
【2】Object.getPrototypeOf() 获取实例的原型
Object.getPrototypeOf(person1)
//浏览器支持:IE9+、Firefox 3.5+、Safari 5+、Opera 12+ 和 Chrome。
【3】多个实例可以共享原型的属性和方法
读取某个对象的某个属性时,先从对象实例本身开始,找到了则返回;没找到则继续搜索原型对象。
【4】hasOwnProperty() 检测一个属性是否存在于实例本身中(不在原型上)
person1.hasOwnProperty("name")
【5】key in object
单独使用in 操作符,会在通过对象能够访问给定属性时返回 true,无论该属性存在于实例中还是原型中。
判断属性是原型中的属性(不在实例上):
function hasPrototypeProperty(object, name){
return !object.hasOwnProperty(name) && (name in object);
}
【6】for (var key in object) { }
使用 for-in 循环时,返回的是所有能够通过对象访问的、可枚举的属性,其中既包括存在于实例中的属性,也包括存在于原型中的属性。
【7】不可枚举属性:hasOwnProperty()、propertyIsEnumerable()、toLocaleString()、toString()、valueOf();constructor 和 prototype
【8】Object.keys(对象) 获取对象上所有可枚举的实例属性,返回一个包含所有可枚举属性的字符串数组
var keys = Object.keys(obj);
【9】Object.getOwnPropertyNames() 获取所有实例属性(无论是否可枚举)
var keys = Object.getOwnPropertyNames(Person.prototype)
// ['constructor','name','age','job','sayName']
3.更简单的原型语法
用一个包含所有属性和方法的对象字面量来重写整个原型对象。
- 出现问题: 原型对象上的 constructor 属性不再指向预想中的构造函数(Person),指向 Object 构造函数
- 解决方法(如需要):手动设置 constructor : Person
function Person(){
}
Person.prototype = {
constructor : Person, // 导致[[Enumerable]]特性被设置为true
name : "Nicholas",
age : 29,
job: "Software Engineer",
sayName : function () {
alert(this.name);
}
};
//兼容 ECMAScript 5 的 JavaScript 引擎可以使用 Object.defineProperty():
Object.defineProperty(Person.prototype, "constructor", {
enumerable: false,
value: Person
});
4.原型的动态性
【1】实例与原型之间的松散连接关系
可以随时为原型添加属性和方法,修改能够立即从实例上反映出来。
5.原生对象的原型
所有原生引用类型(Object、Array、String,等等)都在其构造函数的原型上定义了方法,如 Array.prototype 的 sort() 方法。
可以修改原生对象的原型,可以随时添加方法。
不推荐修改原生对象的原型
6.原型对象的问题
- 所有实例在默认情况下都将取得相同的属性值
- 最大问题是由其共享的本性所导致:函数共享很合适,基本值属性也没问题,但对于包含引用类型值的属性问题比较突出
例如:原型属性有一个是数组,给一个实例的数组添加一项,所有数组都变了====> 不单独使用原型模式