解决原型链的引用类型值问题 --- 组合继承
2013-05-21 20:32
169 查看
首先声明一个概念:我们虽然可以通过实例访问保存在原型中的值,但却不能通过实例重写原型中的值。如果我们在实例中给一个属性赋值,而且该属性与原型中的一个属性同名,那我们就在实例中创建该属性,该属性会屏蔽原型中的那个属性。
但是,虽然不能重写原型中的值,如果原型中包含有引用类型(数组,对象)的值的话,我们可以通过引用来修改原型中的值。
原型中有一个共享的数组属性friends,每一个继承它的实例都可以对它进行修改。显然,每只猫咪都有应该自己的friends,而且不应该决定其他猫咪该有什么friends。好吧,为了猫咪们能够和谐相处,我们做一点点的改进。
//最常用的创建自定义类型的方法
构造函数为每只猫咪创建自己的friends属性,也就是说,把需要共享的属性和方法放在prototype里,而实例自己独立的属性,则放在构造函数里。
在原型链中,由于实例是另一个实例的原型对象这样的关系,我们即使把独立属性放在构造函数里,这个属性最终还是会成为另一个实例的原型里的属性,上面的问题又重演了,怎么办。先举个原型链的例子
Super的独立属性被写在构造函数里了,它的实例都将拥有不同的friends属性,但是,他的实例成了Sub的原型,Sub的实例,又将共享friends属性,怎么破。
分析一下,我们的目的是要Sub继承Super,而且Super中引用类型的属性不被Sub的实例共享。我们能不能像解决猫咪的问题那样,把这个引用类型的应该被独立出来的属性,放在Sub的构造函数里,让Sub的实例们各自生成自己的这个属性。答案,yes
//最常用的继承模式
如此一来,在调用Sub生成实例时,运行了Super函数(super在这里被当成一个普通的函数),为实例生成了各自的friends属性,屏蔽了Sub的原型即Super的实例中的friends属性。这种方法被称为组合继承。组合了经典继承(像sub那样借用super)和原型链继承。
但是,虽然不能重写原型中的值,如果原型中包含有引用类型(数组,对象)的值的话,我们可以通过引用来修改原型中的值。
function Cat(){ }; Cat.prototype.type="Animal"; Cat.prototype.friends=['kitty','cookie']; Cat.prototype.speak=function(){ console.log("喵"); } var cat1=new Cat(); var cat2=new Cat(); cat1.friends.push('apple'); console.log(cat2.friends); console.log(cat1.type); console.log(cat2.type); cat1.speak(); cat2.speak();
原型中有一个共享的数组属性friends,每一个继承它的实例都可以对它进行修改。显然,每只猫咪都有应该自己的friends,而且不应该决定其他猫咪该有什么friends。好吧,为了猫咪们能够和谐相处,我们做一点点的改进。
//最常用的创建自定义类型的方法
function Cat(){ this.friends=['kitty','cookie']; }; Cat.prototype.type="Animal"; Cat.prototype.speak=function(){ console.log("喵"); } var cat1=new Cat(); var cat2=new Cat(); cat1.friends.push('apple'); console.log(cat2.friends); console.log(cat1.type); console.log(cat2.type); cat1.speak(); cat2.speak();
构造函数为每只猫咪创建自己的friends属性,也就是说,把需要共享的属性和方法放在prototype里,而实例自己独立的属性,则放在构造函数里。
在原型链中,由于实例是另一个实例的原型对象这样的关系,我们即使把独立属性放在构造函数里,这个属性最终还是会成为另一个实例的原型里的属性,上面的问题又重演了,怎么办。先举个原型链的例子
function Sub(){ }; function Super(){ this.friends=['Tom','Jack']; } Sub.prototype=new Father(); Super.prototype.species="human"; var instance1=new Sub(); var instance2=new Sub(); instance1.friends.push('danyan'); console.log(instance1.friends);//['Tom','Jack','danyan'] console.log(instance2.friends);//['Tom','Jack','danyan']
Super的独立属性被写在构造函数里了,它的实例都将拥有不同的friends属性,但是,他的实例成了Sub的原型,Sub的实例,又将共享friends属性,怎么破。
分析一下,我们的目的是要Sub继承Super,而且Super中引用类型的属性不被Sub的实例共享。我们能不能像解决猫咪的问题那样,把这个引用类型的应该被独立出来的属性,放在Sub的构造函数里,让Sub的实例们各自生成自己的这个属性。答案,yes
//最常用的继承模式
function Sub(){ Super.apply(this,arguments); }; function Super(){ this.friends=['Tom','Jack']; } Sub.prototype=new Father(); Super.prototype.species="human"; var instance1=new Sub(); var instance2=new Sub(); instance1.friends.push('danyan'); console.log(instance1.friends);//['Tom','Jack','danyan'] console.log(instance2.friends);//['Tom','Tack']
如此一来,在调用Sub生成实例时,运行了Super函数(super在这里被当成一个普通的函数),为实例生成了各自的friends属性,屏蔽了Sub的原型即Super的实例中的friends属性。这种方法被称为组合继承。组合了经典继承(像sub那样借用super)和原型链继承。
相关文章推荐
- 借助构造函数实现继承(解决引用类型问题)
- 解决 命名空间中不存在类型或命名空间名称“App_Code”(是否缺少程序集引用?)的问题
- JS原型链、继承的问题与解决:组合继承、借用构造函数(未完)
- 解决继承窗体或用户控件时“visual继承当前被禁用,因为基类引用设备特定的组件或包含 p/invoke”问题【转】
- 解决继承窗体或用户控件时“visual继承当前被禁用,因为基类引用设备特定的组件或包含 p/invoke”问题(转)
- Swift:(十一)、构造器、自动引用计数、循环引用问题解决、类型转换
- Microsoft.mshtml.dll 添加引用及类型选择错误问题解决办法
- 【转帖】解决继承窗体或用户控件时“visual继承当前被禁用,因为基类引用设备特定的组件或包含 p/invoke”问题
- 关于实现引用类型数组去调用引用类的方法的问题的解决
- 解决继承窗体或用户控件时“visual继承当前被禁用,因为基类引用设备特定的组件或包含 p/invoke”问题
- CS0012: 类型“System.Data.Objects.DataClasses.EntityObject”在未被引用的程序集中定义----问题解决办法
- //组合继承、(原型链继承以及借助构造函数继承)---解决超类传参问题以及共享问题。
- CS0012: 类型“System.Data.Objects.DataClasses.EntityObject”在未被引用的程序集中定义----问题解决办法
- Java泛型 类型擦除在继承中引入的问题及编译器的解决方法
- 递归解决问题的几种类型的排列(二、完整的组合安排)
- 解决 命名空间中不存在类型或命名空间名称“App_Code”(是否缺少程序集引用?)的问题
- CS0012: 类型“System.Data.Objects.DataClasses.EntityObject”在未被引用的程序集中定义----问题解决办法
- 解决 java 中引用的jar包乱码问题
- VS2012 opencv 无法删除“继承的值”问题解决方案
- 解决Eclipse中Java工程间循环引用而报错的问题