浅析原型与原型链以及继承的应用
构造函数,实例,原型与原型对象之间的关系
构造函数有它自己的属性及其方法,其中包括自己定义的属性和方法外,还有两个特殊属性(prototype、constructor);而每个他的实例都会拥有它的所有属性和方法(包括prototype、constructor)constructor则是指向每个实例的构造函数,而prototype 原型 则是一个地址指向原型对象,这个原型对象创建了实例后,只会取得constructor属性,其他的都是从Object继承而来;在Firefox 、 chrome在对象上都支持一个属性"proto";这个原型对象的属性和方法是所有该类实例共享的任何该类实例够可以访问该原型对象的属性和方法。原型对象也是普通的对象,是对象一个自带隐式的 proto 属性,原型也有可能有自己的原型,如果一个原型对象的原型不为 null 的话,我们就称之为原型链,原型链是由一些用来继承和共享属性的对象组成的(有限的)对象链。
想要了解概念,其实只要记住以下几点就好:
1、万物皆对象
2、所有的对象都是由函数创建
3、所有的函数都有prototype属性(原型)
4、所有的对象都有__proto__,所有的对象都有__proto__,指向创建它的函数的prototype
从下图可以看懂原型对象、构造函数、实例对象之间的关系
prototype:构造函数中的属性,指向该构造函数的原型对象。
constructor:原型对象中的属性,指向该原型对象的构造函数
_proto_:实例中的属性,指向new这个实例的构造函数的原型对象
继承
原型链继承
function Type(){
this.colors = ["red", "blue", "green"];
}
Type.prototype.Fun = function(){
};
function SubType(){
}
//继承了Type
SubType.prototype = new Type();
var inst1 = new SubType();
inst1.colors.push("black");
alert(inst1.colors); //"red,blue,green,black"
var inst2 = new SubType();
alert(inst2.colors); //"red,blue,green,black"
优点:能通过instanceOf和isPrototypeOf的检测
注意:给原型添加方法的语句一定要放在原型替换SubType.prototype = new Type();之后
缺点:(1)Type中的属性(不是方法)也变成了SubType的prototype中的公用属性,
如上面例子中的color属性,可以同时被inst1和inst2修改
(2)创建子类型的时候,不能像父类型的构造函数中传递参数。
借用构造函数
function Type(){
this.colors = ["red", "blue", "green"];
}
function SubType(){
//继承了Type
Type.call(this);
}
var inst1 = new SubType();
inst1.colors.push("black");
alert(inst1.colors); //"red,blue,green,black"
var inst2 = new SubType();
alert(inst2.colors); //"red,blue,green"
function Type(name){
this.name = name;
}
function SubType(){
//继承了Type,同时还传递了参数
Type.call(this, "Mingzi);
//实例属性
this.age = 22;
}
var instance = new SubType();
alert(instance.name); //"Mingzi";
alert(instance.age); //22
原理:在子类型构造函数的内部调用超类型构造函数
优点:解决了superType中的私有属性变公有的问题,可以传递参数
缺点:方法在函数中定义,无法得到复用
混合继承
<script>
//使用构造函数+原型的组合模式
function Person( age, name ){
this.age = age;
this.name = name;
}
Person.prototype.show = function(){
alert('父级方法');
}
function Worker(age,name,job){
Person.apply( this, arguments);
this.job = job;
}
Worker.prototype = new Person();
var Person = new Person(14,'张三 ');
var Worker = new Worker (25,'李四','程序员');
</script>
原型式继承
使用场合:没必要构建构造函数,仅仅是想模拟一个对象的时候
function object(o){
function F(){}
F.prototype = o;
return new F();
寄生继承
缺点:方法在函数中定义,无法得到复用
function createAnother(original){
var clone = object(original); //通过调用函数创建一个新对象
clone.sayHi = function(){ //以某种方式来增强这个对象
alert("hi");
};
return clone; //返回这个对象
}
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"
寄生组合继承(最理想)
function inheritPrototype(subType, superType){
var prototype = object(superType.prototype); //创建对象
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象
}
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);//实现继承
SubType.prototype.sayAge = function(){
alert(this.age);
};