您的位置:首页 > 其它

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

2017-06-12 00:07 204 查看
<!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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息