对象的继承

Javascript主要通过原型链实现继承,原型链的构建是通过将一个类型的实例赋值给另一个构造函数的原型实现的。

  由于所有的实例对象共享同一个prototype对象,那么从外界看起来,prototype对象就好像是实例对象的原型,而实例对象则好像"继承"了prototype对象一样。这就是Javascript继承机制的设计思想。

继承方法:

  (1)原型链继承方法:基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。继承是通过创建超类型的实例,并将该实例赋给子类型的原型对象上,实现的本质是重写原型对象,代之以一个新类型实例。

  原型链的第一个问题:引用类型值的原型属性会被所有的实例共享。

         第二个问题:在创建子类型的实例时,不能向超类型的构造函数中传递参数。

  (2)借用构造函数(伪造对象或者经典继承)基本思想是:子类型构造函数的内部调用超类型构造函数,通过使用apply()和call()方法可以在新创建的对象上执行构造函数。

子类型的构造函数里:调用超类型.call(this),来实现继承超类型,相对于原型链,借用构造函数可以在子类型构造函数中向超类型构造函数传递参数。但是call,apply只能继承构造里的信息,不能继承原型里面的信息。

   问题:使用构造函数,方法都在构造函数中定义,因此函数复用就无从谈起。

  (3)组合继承(伪经典继承,javascript常用的继承方式):将原型链和借用构造函数的技术组合到一起 。实现的基本思想:使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,可以在原型上定义方法实现函数复用,又保证了每个实例都有自己的属性。

问题:无论什么时候,都会调用两次超类型的构造函数,一次是在创建子类型原型的时候,另一下次是在子类型构造函数内部。

        //组合继承,将原型链和借用构造函数的技术组合到一起 
	//缺点:都会调用两次超类型的构造函数
		function SuperType(name){
			this.name = name;
			this.color = ["red", "blue", "green"];
		}
		SuperType.prototype.sayName = function() {
			alert(this.name);
		};
		function SubType(name,age) {
			//通过借用构造函数来实现对实例属性的继承
			SuperType.call(this,name); //第二次调用SuperType()
			this.age = age;
			
		}
		//原型链实现对方法的继承
		SubType.prototype = new SuperType();//第一次调用SuperType()
		SubType.prototype.constructor = SubType;
		SubType.prototype.sayAge = function() {
			alert(this.age);
		};
		var instance1 = new SubType("xiyin",22);
		instance1.colors.push("black"); 
		alert(instance1.colors);  //"red,blue,green,black "
		instance1.sayName();   //"xiyin"
		instance1.sayAge();    //22

		var instance2 = new SubType("xixi",23);
		alert(instance2.colors);   //"red,blue,green"
		instance2.sayName();       //"xixi"
		instance2.sayAge();        //23


  (4) 原型式继承 基本思想是:借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。ECMAScript5新增Object.create()方法规范化了原型式继承,这个方法接收两个参数,一个是新对象原型的对象,第二个可选的参数,为新对象定义额外属性的对象

在没有必要创建构造函数时,而只想让一个对象与另一个对象保持类似的情况,原型式继承很好。

//原型式继承,object()对传入其中的对象执行了一次浅复制
	 function object(o) {
	 	 function F() {}
	 	 F.prototype = o;
	 	 return new F();
	 }
	// person.friends不仅属于person所有,而且也会被实例共享,相当于创建了person对象的两个副本
	 var person = {
	 	name: "xiyin",
	 	friends: ["yiyi","haha","fufu"]
	 };
	 var person1 = object(person);
	 person1.name = "xixi";
	 person1.friends.push("taotao");
	 var person2 = object(person);
	 person2.name = "yinyin";
	 person2.friends.push("Bar");
	 alert(person.friends);  //"yiyi,haha,fufu,taotao,Bar"


  (5)寄生式继承 基本思想与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象。使用寄生式继承来为对象添加函数,会由于不能做到函数复用而降低效率,这一点与构造函数模式类似。

  //临时中转函数
	 function obj(o){
	 	function F(){}
	 	F.prototype = o;
	 	return new F();
	 }
	 //寄生函数
	 function create(o){
	 	var f = obj(o);
	 	f.fun = function(){
	 	 return this.name
	 	}
	 	return f;
	 }
	 var person = {
	 	name:"xiyin",
	 	age:24,
	 	family:["哥哥","姐姐","妹妹"]
	 }
	 var box1 = create(person);
	 alert(box1.name);//xiyin


  (6)寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法,基本思想:不必为了指定子类型的原型而调用超类型的构造函数,所需要的就是超类型原型的一个副本而已。(YUI库就是采用该方法实现继承的)

//寄生组合继承来实现继承
	 //寄生函数
	  //临时中转函数
	 function obj(o){
	 	function F(){}
	 	F.prototype = o;
	 	return new F();
	 }
	 function create(box,desk){
	 	var f = obj(box.prototype);
	 	f.constructor=desk;//调整原型构造指针
	 	desk.prototype = f;
	 }
	 function Box(name,age){
	 	this.name = name;
	 	this.age = age;
	 }
	 Box.prototype.run = function(){
	 	return this.name+this.age+"运行中..."
	 }
	 function Desk(name,age){
	 	Box.call(this,name,age);
	 }
	 create(Box,Desk);//这句话用来替代Desk.prototype = new Box();
	 var desk = new Desk("xixi",24);
	 alert(desk.run());//xixi24运行中...


总结:(4),(5),(6)这三种继承方式,还是不够理解,在后续的学习,实践中会继续学习