js.继承

版权声明:欢迎阅读,有误请指正,转载请申明。 https://blog.csdn.net/wx1995sss/article/details/87257080
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script>
//			js的继承实现方式
//			原型链继承
//			构造继承
//			实例继承
//			拷贝继承
//			组合继承
//			寄生组合继承
			//要实现继承,首先得要有一个父类
			console.dir(Object);
			function Animal(name){
				this.name = name;//属性
				this.walking = function(){
					return  this.name + "正在散步";
				}
			}
			//原型方法
			Animal.prototype.eat = function(food){
				return this.name+"正在吃"+food;
			}
			
			
			//原型链的方法
			//核心:将父类的实例作为子类原型
			function Cat(){};
			Cat.prototype = new Animal();
			Cat.prototype.name = "小C";
			var cat = new Cat();
			console.log(cat.name);//小C
			console.log(cat.eat("鱼"));//小C正在吃鱼
			console.log(cat.walking());//小C正在散步
			console.log(cat instanceof Animal);//true
			console.log(cat instanceof Cat);//true
//			特点:
//			实例是子类的实例,也是父类的实例
//			父类新增的原型方法和原型属性,子类都可以访问得到
//			缺点:如果要给子类新增原型属性和方法,必须new 父类的后面才能执行
//			无法实现多继承
//			来自原型对象的所有属性被所有实例共享
//			创建子类实例的时候,没有办法向父类构造函数传参


			/*构造继承
			 * 核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给予子类
			 */
			function Dog(name){
				Animal.call(this);//属性使用对象冒充(call),实际上是改变this指针的指向,继承父类
				//this相当于 new Dog()
				//Students.call(this);
				this.name = name;
			}
			var dog =new Dog("小D");
			console.log(dog.name);//小D
			console.log(dog.walking());//小D正在散步
			//console.log(dog.eat("肉"));报错,不使用原型
			console.log(dog instanceof Animal);//false
			console.log(dog instanceof Dog);//true
			/*特点
			 * 可以实现多继承(call多个父类对象)
			 * 创建子类实例的时候,可以先向父类传参
			 * 缺点:
			 * 不能访问父类原型方法
			 * 实例是子类的实例,不是父类实例
			 * 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
			 */
			/*实例继承
			 * 核心:为父类实例添加新特征,作为子类实例返回	
			 */
			function Sheep(name){
				var anim = new Animal();//创建父类的实例
				anim.name = name;//给实例添加属性
				return anim;//返回属性
			}
			var sheep =new Sheep("小D");
			console.log(sheep.name);//小D
			console.log(sheep.walking());//小D正在散步
			console.log(sheep.eat("草"));//小D正在吃草
			console.log(sheep instanceof Animal);//true
			console.log(sheep instanceof Sheep);//false
			/*特点
			 * 不限制调用方法,不管是new 子类()还是直接子类(),返回的对象具有相同的效果
			 * 缺点
			 * 实例是父类的实例,不是子类的实例
			 * 没有办法实现多继承
			 */
			
			/*拷贝继承
			 * 支持多继承,效率很低,内存占用高(拷贝父类的属性),无法获取父类不可枚举的方法
			 */
			
			/*组合继承
			 * 核心:通过调用父类构造函数,继承父类的属性并保留传参的优点
			 * 然后通过将父类的实例作为子类原型,实现函数复用
			 */
			function Rubbit(name){
				Animal.call(this);
				this.name = name;
			}
			Rubbit.prototype = new Animal();
			Rubbit.prototype.constructor = Rubbit;//修复构造函数的指向(组合继承要构造函数的指向)
			var rubbit = new Rubbit("小R");
			console.log(rubbit.name);//小R
			console.log(rubbit.walking());//小R正在散步
			console.log(rubbit.eat("草"));//小R正在吃草
			console.log(rubbit instanceof Animal);//true
			console.log(rubbit instanceof Rubbit);//true
			/*特点
			 * 可以多继承
			 * 实例是子类的实例也是父类的实例
			 * 可传参
			 * 函数可复用
			 * 可以继承实例的属性和方法,也可以继承原型的属性和方法
			 * 缺点
			 * 调用了两次父类构造函数,生成了两份实例,稍微多占了一些内存
			 */
			/*寄生组合继承
			 * 核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候就不会初始化两次实例方法和属性,避免了组合继承的缺点
			 */
			function Fox(name){
				Animal.call(this);
				this.name =name;
			}
			(function(){
				//创建一个没有实例方法的类
				var obj = function(){};
				//将子类的原型指向父类的原型
				obj.prototype = Animal.prototype;
				//将创建的没有实例方法的类的实例作为构造函数Fox子类的原型
				Fox.prototype = new obj();
			})();
			var fox = new Fox("小F");
			Fox.prototype.constructor =Fox;//修复构造函数的指向
			console.log(fox.name);//小F
			console.log(fox.walking());//小F正在散步
			console.log(fox.eat("鸡"));//小F正在吃鸡
			console.log(fox instanceof Animal);//true
			console.log(fox instanceof Fox);//true
			/*现在有两个类即构造函数,一个是动物类,一个是猫类,
			怎么样让猫类继承动物类的所有属性和方法呢 */
			  	function Animals() {    
    				this.species = "动物";  
				}
				function Cats(name, color) {    
				    this.name = name;    
				    this.color = color;  
				}
				//原型链继承
				/*Cats.prototype = new Animals();
				var cats = new Cats("深毛","黄色");
				console.log(cats.species);*/
				//组合继承
//				Cats.prototype = new Animals();
//				Cats.prototype.constructor = Cats;
//				var cats = new Cats("深毛","黄色");
//				alert(cats.species);
				//寄生组合继承
				function Cats(name, color){
					Animals.call(this);
					this.name = name;    
				    this.color = color; 
				}
				(function(){
					var objs = function(){};
					objs.prototype = Animals.prototype;
					
					console.log(Animals.prototype);//{constructor: ƒ}
					console.log(Cats.prototype);//{constructor: ƒ}
					
					Cats.prototype = new objs();
//					Cats.prototype = objs.prototype; 将上面的改为此式,一样有效
					//原型是对象属性的备用来源。
					//每个对象除了拥有自己的属性外,几乎都包含一个原型。原型是另一个对象,是对象的一个属性来源。
					//当开发人员访问一个对象不包含的属性时,就会从对象原型中搜索属性,接着是原型的原型,依此类推。
					//所以这里new objs()没有属性,Cats.prototype访问了 objs()的原型,即objs.prototype
					console.log(new objs());//objs {}
					console.log(Cats.prototype);//Animals {}
					console.log(Cats.prototype.constructor);//ƒ Animals() {    this.species = "动物";  }
				})();
				Cats.prototype.constructor = Cats;//这里Cats的原型是Animals,constructor是Cats,constructor存储着原型的指针,即Cats能同时访问Animals和自身
				var cats = new Cats("深毛","黄色");
				console.log(cats.species);
				console.log(cats.color);
				console.log(cats.name);
				console.log(Cats.prototype);//Animals {constructor: ƒ}
				console.log(Cats.prototype.constructor);//ƒ Cats(name, color){Animals.call(this);this.name = name;  this.color = color; }
		</script>
	</head>
	<body>
	</body>
</html>

猜你喜欢

转载自blog.csdn.net/wx1995sss/article/details/87257080