在JavaScript中,每个对象皆有原型。普通对象有_proto_(原型)属性,创建的每一个函数有prototype(原型属性),这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。简单来说,如:先创建一个构造函数:
function Person(){
}
为构造函数的原型定义属性和方法:
Person.prototype.name="wgq";
Person.prototype.age=18;
Person.prototype.sayage = function(){
alert(this.age);
}
这样,为构造函数的原型定义属性和方法就完成了,下面可以创建实例,调用原型里的属性和方法:
var person =new Person();
person.sayage(); //18
alert(person.name); //"wgq"
简单来说,JavaScript中的对象上方有一容器(原型),可以在这容器(原型)中储存属性和方法,对象实例化后也可以访问到。
另外,每一个原型对象都会自动获得一个constructor(构造函数)属性,该属性指向prototype所在函数的指针。
举个例子:
alert(Person.prototype.constructor == Person) //"true"
在原型中定义的属性和方法,可以通过对象实例重写来进行覆盖。
function Person(){};
Person.prototype.name="wgq";
Person.prototype.age=18;
Person.prototype.sayage = function(){
alert(this.age);
};
var person1 =new Person();
var person2 =new Person();
person2.name="qwe";
alert(person1.name); //"wgq"
alert(person2.name); //"qwe"
属性及方法覆盖的原因是因为在代码搜索的过程中,会先在对象实例中找具有具体名字的属性,如果找到直接结束,如果找不到,才会继续去原型对象中寻找。
原型对象有一个缺点:他的所有属性和方法都是共享的。请看以下例子:
function Person(){};
Person.prototype.name="wgq";
Person.prototype.age=18;
Person.prototype.frinds=["a","b"];
Person.prototype.sayage = function(){
alert(this.age);
};
var person1 =new Person();
var person2 =new Person();
person1.frinds.push("c");
alert(person1.frinds); // "a,b,c"
alert(person2.frinds); // "a,b,c"
解决方法是,可以组合使用构造函数和原型。用构造函数来定义各自的属性,用原型来定义方法和共享属性。
下面是继承,继承主要是通过原型链来实现的。
Father(){
};
Son(){
};
Son.prototype =new Father() //继承了Father
这样的继承,实质上是把Father对象和该对象的原型写进Son对象的容器(原型)中
Son对象的原型(Son.prototype)包含了Father对象与Father.prototype(Father的原型)通过实例化Son对象,该实例可以调用
1. Son构造函数的属性和方法
2. Father构造的属性和方法
3. Father.prototype中的属性和方法
这就是原型链:
Son.prototype ->Father对象
Son.prototype,prototype->Father.prototype
最后除了这些,还有别忘了最初的Object,他是所有对象的父亲,所以:
Father.prototype->Object.