高级面向对象 之 继承(拷贝继承)
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>
相关文章推荐
- JavaScript高级程序设计之面向对象的程序设计之继承之原型链 第6.3.1讲笔记
- 高级面向对象 之 原型继承
- JS高级知识(面向对象,原型,原型链理解,继承)
- JavaScript高级程序设计之面向对象的程序设计之继承之寄生组合式继承第6.3.6讲笔记
- JavaScript高级 面向对象(8)--浅拷贝代码实现
- JavaScript高级 面向对象(9)--深拷贝代码实现
- js面向对象的继承--拷贝,类式继承,原型继承
- JavaScript面向对象(4)——最佳继承模式(深拷贝、多重继承、构造器借用、组合寄生式继承)
- JS高级 - 面向对象5(继承,引用)
- 面向对象的继承(拷贝继承)
- JavaScript高级程序设计【面向对象-继承】
- js高级程序设计--面向对象的理解(包括原型和继承)
- JavaScript高级程序设计之面向对象的程序设计之继承之借用构造函数第6.3.2讲笔记
- Java-面向对象(高级篇)--继承的基本概念
- JavaScript高级 面向对象(5)--最简单的继承方式,混入mix
- JavaScript高级 面向对象(7)--深拷贝与浅拷贝
- Java-面向对象(高级篇)--继承的进一步研究
- JavaScript高级程序设计之面向对象的程序设计之继承之原型式继承第6.3.4讲笔记
- 高级面向对象之 类式继承
- js面向对象、原型及继承(javaScript高级程序设计第3版)