原型和闭包是Js语言的难点,此文主要讲原型。
每一个方法都有一个属性是 prototype
每一个对象都有一个属性是 _proto_
一旦定义了原型属性或原型方法,则所有通过该构造函数实例化出来的所有对象,都继承了这些原型属性和原型方法,这是通过内部的_proto_链来实现的。
/* Js所有的函数都有一个prototype属性,这个属性引用了一个对象,即原型对象,也简称原型。这个函数包括构造函数和普通函数,我们讲的更多是构造函数的原型,但是也不能否定普通函数也有原型。
每一个方法都有一个属性叫做原型(prototype)
prototype的定义:不需要显式地声明一个prototype属性,因为在每一个构造函数中都有它的存在。 */
譬如普通函数:
function Test(){
}
console.log("exp1 : " + Test.prototype); // [object Object]
console.log("exp1 : " + Test.prototype instanceof Object) //true
譬如构造函数,也即构造对象。首先了解下通过构造函数实例化对象的过程。
function A(x){
this.x=x;
}
var obj=new A(1);
实例化obj对象有三步:
1. 创建obj对象:obj=new Object();
2. 将obj的内部__proto__指向构造他的函数A的prototype,obj.constructor.prototype与的内部_proto_是两码事,实例化对象时用的是_proto_,obj是没有prototype属性的,但是有内部的__proto__,通过__proto__来取得原型链上的原型属性和原型方法
3.将obj作为this去调用构造函数A,从而设置成员(即对象属性和对象方法)并初始化。
一旦定义了原型属性或原型方法,则所有通过该构造函数实例化出来的所有对象,都继承了这些原型属性和原型方法,这是通过内部的_proto_链来实现的。
譬如: A.prototype.say=function(){alert("Hi")};
那所有的A的对象都具有了say方法,这个原型对象的say方法是唯一的副本给大家共享的,而不是每一个对象都有关于say方法的一个副本。
以下通过几个实例来深入理解prototype:
/* exp2:start...*/
/*
给prototype添加属性
prototype是一个对象,因此,你能够给它添加属性。
你添加给prototype的属性将会成为使用这个构造函数创建的对象的通用属性。 */
function Fish(name, color){
this.name = name;
this.color = color;
}
Fish.prototype.livesIn = ‘water‘;
Fish.prototype.price = 20;
//构造
var fish1 = new Fish(‘mackarel‘, ‘gray‘);
var fish2 = new Fish(‘goldfish‘, ‘orange‘);
var fish3 = new Fish(‘salmon‘, ‘white‘);
for (var i = 1; i <= 3; i++){
var fish = eval(‘fish‘ + i); // 取得指向这条鱼的指针
console.log("exp2 : " + fish.name + ‘,‘ + fish.color + ‘,‘ + fish.livesIn + ‘,‘ + fish.price);
}
//mackarel,gray,water,20
//goldfish,orange,water,20
//salmon,white,water,20
/* exp2:end...*/
/* exp3:start...*/
/* 当一个对象被创建时,这个构造函数将会把它的属性prototype赋给新对象的内部属性__proto__。这个__proto__被这个对象用来查找它的属性。 */
function Employee(name, salary){
this.name = name;
this.salary = salary;
}
/* Employee的所有对象都具有getSalary()和addSalary()方法,此原型对象的这两个方法是是唯一的,也是共享的,
并非Employee的所有对象都拥有此方法(非一一对应,而是多对一) */
Employee.prototype.getSalary = function getSalaryFunction(){
return this.salary;
}
Employee.prototype.addSalary = function addSalaryFunction(addition){
return this.salary = this.salary + addition;
}
var boss1 = new Employee(‘Jon‘, 200000);
var boss2 = new Employee(‘Kim‘, 100000);
var boss3 = new Employee(‘Sam‘, 150000);
console.log("exp3 : " + boss1.getSalary()); // 输出 200000
console.log("exp3 : " + boss2.getSalary()); // 输出 100000
console.log("exp3 : " + boss3.getSalary()); // 输出 150000
console.log("exp3 : " + boss1.addSalary(5000)); // 输出 205000
console.log("exp3 : " + boss2.addSalary(5000)); // 输出 105000
console.log("exp3 : " + boss3.addSalary(5000)); // 输出 155000
/* exp3:end...*/
/* exp4:start...*/
function F() {}
var i = new F();
console.log("exp4 : i.prototype : " + i.prototype + " , F.prototype : " + F.prototype ,", i.__proto__ : " + i.__proto__ + " , F.__proto__ : " + F. __proto__);
//exp4 : i.prototype : undefined , F.prototype : [object Object] , i.__proto__ : [object Object] , F.__proto__ : function Empty() {}
/* exp4:end...*/