高级面向对象 之 继承(拷贝继承)

本文深入讲解JavaScript中的继承机制,包括属性继承与方法继承的具体实现方式,并通过实例详细解释如何使用call方法实现属性继承,以及如何利用for-in实现方法继承的同时避免影响原始对象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>对象的继承</title>
	</head>
	<body>
		<script>
			1.什么是继承
				1>:在原有对象的基础上,略作修改,得到一个新的对象
				2>:不影响原有对象的功能
			2.如何添加继承
				1>:属性: call
				2>:方法: for in  (拷贝继承)
			3.例子  
				1>: 拖拽
				
			主题 :
				继承 :子类不影响父类,子类可以继承父类的一些功能(代码的复用)
			首先我们写一个面向对象的例子(有属性,有方法):
			
			function CreatePerson(name,sex){          // 父类
				this.name = name;
				this.age = age;
			}
			
			CreatePerson.prototype.showName = function(){
				alert(this.name);
			}
			
			var p1 = new CreatePerson('小明','男');
			p1.showName(); // 小明
			
			然后我们来实现继承:
			function CreateStar(name,sex,job){                // 子类
				CreatePerson(name,sex);  // 错误写法
				this.job = job;
			}
			
			该例子中我们继承就是为了实现 属性name和sex的继承,我们可能会认为直接在子类的构造函数中调用父类的构造函数,
			这样做是没错,但是存在作用域的问题, 子类中调用的父类构造函数是属于window对象的,那么添加的两个属性name和
			sex 就属于window对象,而不属于子类对象,那我们该怎么做呢?我们可以通过使用call方法,修改父类的作用域
			
			正确写法应该是:
			function CreateStar(name,sex,job){               // 子类
				 // 这样就可以正确的继承父类的属性了
				CreatePerson.call(this,name,sex);
				this.job = job ;
			}
			
			总结 : 属性继承的方式 -> 采用call的形式调用父类的构造函数
			
			那么我们该如何实现方法的继承呢 ?如demo中 我们想把父类的 showName()方法给继承过来,该怎么办呢?
			
			想到一种方法  : 把父类的原型 赋值给 子类的原型
			既 : CreateStar.prototype = CreatePerson.prototype;
			此时子类对象就拥有了父类对象的所有方法如 :
			
			var p2 = new CreateStar('黄晓明','男','演员');
			p2.showName(); // 黄晓明
			子类此时可以调用父类的方法,并输出正确结果,说明此时我们已经实现了子类方法的继承。
			
			但是这里存在一点小问题,我们会发现:
			我们把一个原型对象赋值给另外一个原型对象,这是一种对象的引用(对象赋值给对象,这是一种引用关系),
			对象的引用会造成他们值的地址在内存的同一个地址上,这样的话如果我们修改了其中一个对象,
			另外一个对象也会被修改.
			
			如下 我们给子类对象添加一个方法:
			CreateStar.prototype.showJob = function(){};
			此时我们在控制台发现,父类对象也有了一个showJob()方法,既我们无意间修改了父类,这显然不符合继承的规则,
			继承的时候不能影响原有对象的功能,那我们该怎么解决这个问题呢?
			  
			解决办法 : 对对象进行复制,而不是引用
			
			下面我们来看demo2:
			
			var a ={
				name : 小明
			};
			// 对象a赋值给对象b,对象赋值给对象,这是一种引用关系,此时他们的值会指向内置中的同一个地址,
			// 当我们修改其中一个对象时,另外一个对象也会被修改
			var b =a;
			b.name = '小强';
			alert(a.name);  // 小强
			我们会发现,将对象a 赋值给对象b,然后修改对象b的name属性,结果对象a的name 属性值也被修改了,
			显然这不是我们想要的.怎么解决呢?
			我们可以通过基本类型值赋值的形式来解决这个问题(值传递的方式)
			
			demo1:
			代码:
			var a = {
				name : '小明'
			};
			var b ={};
			function extend(obj1, obj2){    // 封装函数
				for(var attr in obj2){
					obj1[attr] = obj2[attr];
				}
			}
			extend(b,a);
			b.name = '小强';
			alert(a.name);  // 小明 
			通过 for - in 遍历,使用基本类型值赋值的形式很好地解决了我们这个问题.
			
			这种方法也可以用来解决我们最上面的问题(CreatePerson对象与CreateStar对象方法的继承问题)
			
			demo2:
			function CreatePerson(name,sex){    // 父类
				this.name = name;
				this.sex = sex;
			}
			CreatePerson.prototype.showName= function(){
				alert(this.name);
			}
			
			function CreateStar(name,sex,job){     // 子类
				CreatePerson.call(this,name,sex);
				this.job = job;
			}
			
			function extend(obj1,obj2){           // 方法继承的封装函数
				for(var attr in obj2){
					obj1[attr]= obj2[attr];
				}
			}
			
			extend(CreateStar.prototype,CreatePerson.prototype);  // 方法继承
			
			// 此时我们就可以实现了 CreateStar对CreatePerson 的继承,同时修改他们中的任意一个,
			//  对另外一个也没有影响
			
			那么问题又来了, 对于demo1中,name的值是字符串,是基本类型,这样解决没问题,可是 通过for in 遍历的
			项,(CreatePerson.prototype和CreatePerson.prototype),他们里面是函数,我们前面介绍过,函数是对象类型,
			那么函数属于对象类型,我们通过for-in遍历原型对象,然后赋值(函数赋给函数)为什么不会出现问题呢?
			
			其实呢,函数虽然是对象类型,但是他跟对象类型还是有点区别的,函数呢它其实是不能被修改的,它只能被改变(赋值)
			什么意识呢? 我们看下面的例子
			
			demo3:   (这里是修改,修改后会影响另外一个对象)
				var a = [1,2,3];
				var b = a;
				b.push(4);
				alert(a); // 1,2,3,4
				
			demo4:  (这里是重新赋值,对象b又重新生成了,所以他跟对象a之间的引用链条就断开了,它俩之间就没关系了)
				var a = [1,2,3];
				var b = a;
				b = [1,2,3,4];
				alert(a); // 1,2,3
				
			因为: 函数虽然是对象类型,但是只要你一赋值,它必然不会出现相互影响,因为它没法修改,只能赋值故,
			根据函数的这个特点我们可以利用for -in 实现对象方法的继承
			
			总结: 函数的特点: 函数虽然是对象类型,但是函数是不能修改的,函数只能重新赋值
			
			总结 : 方法的继承方法 : 使用 for in, 这种方法也叫做拷贝继承(JQuery也是采用的拷贝继承,当然它的
								   实现比较复杂点)
		</script>
	</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值