<!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>
高级面向对象 之 继承(拷贝继承)
最新推荐文章于 2022-05-23 09:29:19 发布