javascript中关于继承的理解
首先,你要理解在javascript中,每当一个新函数创建时,都会生成一个prototype属性,我们管它叫做原型对象。看一个例子:
function foo(){
this.name='qiangqiang';
this.age=23;
this.colors=['red','orange','yellow'];
}
foo.prototype.z=2;
console.log(foo.prototype);
查看一下foo.ptototype
看以看到foo的原型对象的结构,有一个构造函数,__proto__属性,还有一个我们在原型对象里面创建的属性,其中前两个是prototype属性默认的。
这时,我们再继续创建一个foo的实例对象。
var f=new foo();
console.log(f.__proto__);
再看一下结果
与上面的结果是相同的,注意,这里的实例化出的对象f没有prototype属性,它只有一个__proto__属性而且是指向foo.prototype的。所以当我们,
console.log(f.z)的时候,会打印出2,而这也正是沿着原型链向上查找的原因。
接下来:
console.log(f)
我们看到了对象f的所有属性。
我们在写一段这样的代码。
function nextfoo(){
}
nextfoo.prototype=new foo();
console.log(nextfoo.prototype);
我们可以看到,这时nextfoo.prototype属性和f的属性是一致的,这里其实就叫做重写了nextfoo的原型对象,在他的原型对象里面包括了,foo中定义的name,age属性、__proto__属性(指向foo的原型对象)、constructor属性(foo的构造函数)。
这时,我们在写这样一段代码
var nextf=new nextfoo();
nextf.colors.push('black');
console.log(nextf.colors);
var nextf2=new nextfoo();
console.log(nextf2.colors);
我们可以看到由于都是引用的原型对象中的属性,因此对象实例之间会相互影响。
还有一个问题,
console.log(f.name);
console.log(f.age);
那么这里的name和this到底是沿着原型链向上查找到的呢,还是自己本身创建的呢。我们在来试一下。
console.log(f.hasOwnProperty('name'));
通过这个,我们看以判断出name是属于自身的属性,这里的原因就是this的绑定的问题啦,建议先把http://www.cnblogs.com/qqqiangqiang/p/5316973.html理解了,其实this是隐式绑定在了f对象上,因此会创建出属于自身的属性。
明白了以上这些,那么理解继承就不是问题啦。。。
实现继承主要是通过原型链来实现的。
其基本思想是利用原型链让一个引用类型继承另一个引用类型的属性和方法。
实现原型链有一种基本模式,其代码大致如下。
function SuperType(){
this.property=true;
}
SuperType.prototype.getSuperValue=function(){
return this.property;
}
function SubType(){
this.subproperty=false;
}
SubType.prototype=new SuperType();
SubType.prototype.getSubValue=function(){
return this.subproperty;
}
var instance=new SubType();
alert(instance.getSuperValue());// true
以上代码定义了两个类型:SuperType和SubType。每个类型分别有一个属性和方法。他们的主要区别是SubType继承了SuperType,而继承是通过创建SuperType的实例,并将该实例赋给SubType.prototype实现的。实现的本质是重写原型对象,代之以一个新类型的实例。换句话说,原来存在于SuperType的实例中的所有属性和方法,现在也存在于SubType.prototype中了。
确定原型和实例的关系有以下几种方法:
alert(instance instanceof Object);//true
alert(instance instanceof SupperType);//true
alert(instance instanceof SubType);//true alert(Object.prototype.isPrototypeOf(instance));//true
alert(SupperType.ptototype.isPrototypeOf(instance));//true
alert(SubType.prototype.isPrototypeOf(instance));//true
3、谨慎的定义方法
给原型添加方法的代码一定要放在替换原型的语句之后,例子:
function SuperType(){
this.property=true;
}
SuperType.prototype.getSupervalue=function(){
return this.property;
};
function SubType(){
this.subproperty=false;
}
SubType.prototype=new SuperType(); SubType.ptototype.getSubValue=function(){
return this.subproperty;
}
SuperType.prototype.getSuperValue=function(){
return fasle;
};
var instance=new SubType();
alert(instance.getSuperValue());//false
var instance1=new SupperType();
alert(instance1.getSuperValue());//true;
当通过SubType的实例调用getSuperValue()时,调用的就是这个重写的方法,但通过SuperType的实例调用时还是原来的那个方法。
还有一点需要注意,就是通过原型链继承的时,不能使用对象字面量创建原型方法,这样做就会重写原型链,
原型链导致的问题:
function SuperType(){
this.colors=['red','orange','yellow'];
}
function SubType(){}
SubType.prototype=new SuperType();
console.log(SubType.prototype);
var instance1=new SubType();
instance1.colors.push('black');
console.log(instance1.colors); //'red,orange,yellow,black'
var instance2=new SubType();
console.log(instance2.colors);//'red,orange,yellow,black'
导致所有的SubType的实例都会共享这一个colors属性。
(**解释一下这个原因,由于是重写了原型对象,所以SubType的prototype原型原型对象里面有一个__proto__属性指向SuperType的原型对象,还有colors这个数组,所以SubType的所有实例都是共享这个数组的**)
还有一个问题就是,在创建子类型的实例的时候,不能向超类型的构造函数中传递参数。实际上,应该是没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数。
鉴于以上的两个问题,实践中很少会单独使用原型链。
继承的其他方式:
1、借用构造函数
function SuperType(name){
this.name=name;
}
function SubType(name){
SuperType.call(this,name);
this.age=29;
}
var instance=new SubType('Nicholas');
alert(instance.name);//Nicholas
var instance2=new SubType('dongzhiqiang');
alert(instance2.name);
这里最关键的是对于this的理解,SuperType.call(this,name)的意思是把SuperType函数的this对象绑定到SubType函数的this对象,所以说这里的关键就是如何判断SubType函数的this对象指向哪里,具体参考http://www.cnblogs.com/qqqiangqiang/p/5316973.html 可以看出this是分别指向instance和instance2对象的,换句话说,它就相当于分别在不同的对象中创建了colors这个数组。所以说不共享统一colors自然就不互相影响。
问题:方法都在构造函数中定义,因此函数的复用无从谈起。
2、组合继承
function SuperType(name){
this.name=name;
this.colors=['red','orange','yellow'];
}
SuperType.prototype.sayName=function(){
console.log(this.name);
}
function SubType(name,age){
SuperType.call(this,name);
this.age=age;
}
SubType.prototype=new SuperType();
SubType.prototype.constructor=SubType;
SubType.prototype.sayAge=function(){
console.log(this.age);
};
var instance1=new SubType('Nicholas',29);
instance1.colors.push('black');
alert(instance1.colors);
instance1.sayName();
instance1.sayAge(); var instance2=new SubType('Greg',23);
alert(instance2.colors);
instance2.sayName();
instance2.sayAge();
组合继承避免了原型链和借用构造函数的缺陷,融合了他们的优点,成为javascript中最常用的继承模式。但是他的问题就是无论在什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。而且还会造成prototype已经有相应属性,而又在新创建的对象上创建了实例属性name和colors.
3、原型式继承
function object(o){
function F(){
F.prototype=o;
}
return new F(); }
ECMAScript5通过新增Object.create()方法(类似于上面的object方法)规范化了原型式继承。这两个方法接收两个参数:一个用作新对象原型的对象和一个为新对象定义额外属性的对象。
var person={
name:'Nicholas',
friends:['Shelby','court','van']
};
var anthoerPerson=Object.create(person);
anthoerPerson.name='Greg';
anthoerPerson.push('Rob');
var yetAnotherPerson=Object.create(person);
yetAnotherPerson.name='Linda';
yetAnotherPerson.friends.push('Barible');
alert(person.friends); //'Shelby,Court,Van,Rob,Barible'
缺点同原型模式一样,会共享同一个值造成互相影响。
4、寄生式继承
寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个用于封装继承过程的函数,该函数在内部以某张方式来增强对象,最后再像是真地做了所有工作一样返回对象。
function object(o){
function F(){
F.prototype=o;
}
return new F(); }
function createAnother(original){
var clone=object(original);
clone.sayHi=function(){
alert('Hi');
};
return clone;
}
var person={
name:'Nicholas',
friends:['Shary','Court','Van']
}
var anotherPerson=createAnother(person);
anotherPerson.sayHi(); 5、寄生组合式继承
function inheritPrototype(subType,superType){
var prototype=Object(superType.prototype);
prototype.constructor=subType;
subType.prototype=prototype;
}
function SuperType(name){
this.name=name;
this.colors=['red','orange','yellow'];
}
SuperType.prototype.sayName=function(){
alert(this.name);
}
function SubType(name,age){
SuperType.call(this,name);
this.age=age;
}
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge=function(){
alert(this.age);
}
var sub=new SubType('maidi',36);
sub.sayName();
sub.sayAge();
其高效率体现在它只调用了一次SuperType构造函数,并且因此避免了在SubType.prototype上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;开发人员普遍认为组合式继承是引用类型最理想的继承范式。
javascript中关于继承的理解的更多相关文章
- 深入理解JavaScript中的继承
1前言 继承是JavaScript中的重要概念,可以说要学好JavaScript,必须搞清楚JavaScript中的继承.我最开始是通过看视频听培训班的老师讲解的JavaScript中的继承,当时看的 ...
- JavaScript中的继承(原型链)
一.原型链 ECMAScript中将原型链作为实现继承的主要方法,基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法. 实例1: function SupType() { this.pro ...
- 彻底搞懂JavaScript中的继承
你应该知道,JavaScript是一门基于原型链的语言,而我们今天的主题 -- "继承"就和"原型链"这一概念息息相关.甚至可以说,所谓的"原型链&q ...
- JavaScript学习13 JavaScript中的继承
JavaScript学习13 JavaScript中的继承 继承第一种方式:对象冒充 <script type="text/javascript"> //继承第一种方式 ...
- 浅谈JavaScript中的继承
引言 在JavaScript中,实现继承的主要方式是通过原型链技术.这一篇文章我们就通过介绍JavaScript中实现继承的几种方式来慢慢领会JavaScript中继承实现的点点滴滴. 原型链介绍 原 ...
- 浅谈 JavaScript 中的继承模式
最近在读一本设计模式的书,书中的开头部分就讲了一下 JavaScript 中的继承,阅读之后写下了这篇博客作为笔记.毕竟好记性不如烂笔头. JavaScript 是一门面向对象的语言,但是 ES6 之 ...
- 关于JavaScript中实现继承,及prototype属性
感谢Mozilla 让我弄懂继承. JavaScript有八种基本类型,函数属于object.所以所有函数都继承自object.//扩展:对象,基本上 JavaScript 里的任何东西都是对象,而且 ...
- javascript中各种继承方式的优缺点
javascript中实现继承的方式有很多种,一般都是通过原型链和构造函数来实现.下面对各种实现方式进行分析,总结各自的优缺点. 一 原型继承 let Super = functioin(name = ...
- javascript中实现继承的几种方式
javascript中实现继承的几种方式 1.借用构造函数实现继承 function Parent1(){ this.name = "parent1" } function Chi ...
随机推荐
- java基础IO流综合加习题
IO流初学者在学习时都有一点迷糊,今天我们就讲讲IO流,希望通过讲解可以帮助大家 IO流分为字节流,字符流,缓冲流.我们只要记住这三个就可以了. 1*字节流有:字节输入流(FileInputStrea ...
- 初识JavaWEB
小荷才露尖尖角,早有蜻蜓立上头 首先,你需要知道你要学习哪些知识,掌握哪些技术?且听我娓娓道来. 第一阶段:HTML ,CSS ,JavaScript这三个是必须要掌握的,也是最基础的了.其实HEML ...
- Mac OS 上 CRT 的终端设置
这种设置完全是个人习惯, 切勿效仿!!! 整个终端是 白底黑字 显示方式(奇葩中的奇葩) 1) ANSI Color & Use color scheme 同时勾选 2) Characte ...
- windows 上搭建 sftp 服务器 --freesshd
Linux 下 sftp 默认都会安装的, Windows 就没有了.网上搜的资料发现比较好用的是 freesshd,免费版中最好用的. 1,下载:http://www.freesshd.com/?c ...
- [MFC美化] Skin++使用详解-使用方法及注意事项
主要分为以下几个方面: 1.Skin++使用方法 2.使用中注意事项 一. Skin++使用方法 SkinPPWTL.dll.SkinPPWTL.lib.SkinPPWTL.h ,将三个文件及相应皮肤 ...
- Webupload + MVC 之上传下载
最近工作中用到了 MVC 的上传及下载 , 写下感受 本项目中用到的是百度的webuploader <!--引入Jquery--> <script src="~/Conte ...
- 让webstorm支持新建.vue文件
1. 首先安装vue插件,安装方法: file-->setting --> plugin ,点击plugin,在内容部分的左侧输入框不用输入任何东西,直接点击下图中的按钮. 如下图所 ...
- 转:NSString什么时候用copy,什么时候用strong
大部分的时候NSString的属性都是copy,那copy与strong的情况下到底有什么区别呢? 比如: @property (retain,nonatomic) NSString *rStr; @ ...
- Makfile文件编写
一.make是什么 GNU make是一个工程管理器,专门负责管理.维护较多文件的处理,实现自动化编译.如果一个工程项目中,有成百上千个代码源文件,若其中一个或多个文件进过修改,make就需要能够自动 ...
- 可参考的gulp资源
可参考的gulp资源 入门:https://segmentfault.com/a/1190000000435599 比较详细:https://markpop.github.io/2014/09/17/ ...