JavaScript是动态语言,可以在任何时候向对象添加属性:
function People(){
this.name = 'JiaoMaiQi';
this.gender = 'Male';
}
var peopleObj1 = new People();
peopleObj1.age = 22;
console.log(peopleObj1.age); //22
var peopleObj2 = new People();
console.log(peopleObj2.age); //undefined
age属性附加在peopleObj1实例上,而peopleObj2实例没有age属性,因为age属性只在peopleObj1上定义了,因此peopleObj2.age为undefined。那么,如果我们想添加一个属性并让这个属性被所有的实例共享,应该怎么办?答案就是:Prototype。
Prototype是一个对象,默认情况下与js中的任意一个函数或对象有关,唯一的区别在于函数的prototype属性是可访问和可修改的,而对象的proto属性是不可见的。
默认情况下任何一个函数包含Prototype属性。
prototype对象是一种特殊类型的可枚举对象,可以将需要的附加属性添加到其上,这些属性将在其构造函数的所有实例之间共享。
那么,我们使用函数的prototype来添加age属性,以便于所有对象中都可以访问到:
function People(){
this.name = 'JiaoMaiQi';
this.gender = 'Male';
}
People.prototype.age = 22;
var peopleObj1 = new People();
console.log(peopleObj1.age); //22
var peopleObj2 = new People();
console.log(peopleObj2.age); //22
使用字面量或通过new关键字和构造函数的方式创建每一个对象都包含_proto_属性,该属性指向创建该对象的函数的原型对象。
function People(){
this.name = 'JiaoMaiQi';
this.gender = 'Male';
}
//People.prototype.age = 22;
var peopleObj1 = new People();
console.log(People.prototype === peopleObj1._proto_); //true
上面例子可以看出,函数通过函数名称.prototype方式访问到原型对象,但是对象实例并没有暴露出prototype属性,而是使用_prototype_来访问它。
Object对象的原型。
因原型对象在对象中是不可见的,因此使用Object.getPrototypeOf(obj)方法来访问实例的原型对象。
function People(){
this.name = 'JiaoMaiQi';
this.gender = 'Male';
}
var peopleObj = new People();
People.prototype.sayHi = function () {
console.log("Hi");
}
var peopleObj1 = new People();
var proto = Object.getPrototypeOf(peopleObj1); //return People's prototype object
console.log(proto.constructor); //return People function
Object原型对象包含:属性、方法。
属性描述constructor 返回创建该实例的构造函数_proto_指向创建该实例的构造函数的原型对象。
修改原型。
每个对象都能链接到函数的原型对象。如果更改了函数的原型,则只有新对象将链接到更改后的原型。所有其他现有对象任然链接到旧的函数原型。下面实例来演示下:
function People(){
this.name = 'JiaoMaiQi';
this.gender = 'Male';
}
People.prototype.age = 22;
var peopleObj1 = new People();
console.log('peopleObj1.age='+ peopleObj1.age);
var peopleObj2 = new People();
console.log('peopleObj2.age='+ peopleObj2.age);
People.prototype = { age: 25 };
var peopleObj3 = new People();
console.log('peopleObj3.age='+ peopleObj3.age);
console.log('peopleObj1.age='+ peopleObj1.age);
console.log('peopleObj2.age='+ peopleObj2.age);
控制台输出如下:
使用原型。
原型被JavaScript引擎用来做两件事:
- 查找对象的属性和方法
- 在javascript中实现继承
function People(){
this.name = 'JiaoMaiQi';
this.gender = 'Male';
}
People.prototype.sayHi = function(){
console.log("Hi");
}
var peopleObj = new People();
peopleObj.toString();
在上面实例中,toString()方法在People中并没有定义,那他是从哪里来的呢?
在这里,原型出现了。首先JavaScript引擎检查peopleObj是否含有toString()方法?如果没有,那么它会使用peopleObj的_proto_链接指向People函数的原型对象。如果仍旧没有找到,继续向上检查Object函数的原型对象,因为所有对象都是从JavaScrpt中的Object派生的。因此可以在object函数原型对象中找到toString()方法,因此可以调用peopleObj.toString()。