首先,你要理解在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中关于继承的理解的更多相关文章

  1. 深入理解JavaScript中的继承

    1前言 继承是JavaScript中的重要概念,可以说要学好JavaScript,必须搞清楚JavaScript中的继承.我最开始是通过看视频听培训班的老师讲解的JavaScript中的继承,当时看的 ...

  2. JavaScript中的继承(原型链)

    一.原型链 ECMAScript中将原型链作为实现继承的主要方法,基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法. 实例1: function SupType() { this.pro ...

  3. 彻底搞懂JavaScript中的继承

    你应该知道,JavaScript是一门基于原型链的语言,而我们今天的主题 -- "继承"就和"原型链"这一概念息息相关.甚至可以说,所谓的"原型链&q ...

  4. JavaScript学习13 JavaScript中的继承

    JavaScript学习13 JavaScript中的继承 继承第一种方式:对象冒充 <script type="text/javascript"> //继承第一种方式 ...

  5. 浅谈JavaScript中的继承

    引言 在JavaScript中,实现继承的主要方式是通过原型链技术.这一篇文章我们就通过介绍JavaScript中实现继承的几种方式来慢慢领会JavaScript中继承实现的点点滴滴. 原型链介绍 原 ...

  6. 浅谈 JavaScript 中的继承模式

    最近在读一本设计模式的书,书中的开头部分就讲了一下 JavaScript 中的继承,阅读之后写下了这篇博客作为笔记.毕竟好记性不如烂笔头. JavaScript 是一门面向对象的语言,但是 ES6 之 ...

  7. 关于JavaScript中实现继承,及prototype属性

    感谢Mozilla 让我弄懂继承. JavaScript有八种基本类型,函数属于object.所以所有函数都继承自object.//扩展:对象,基本上 JavaScript 里的任何东西都是对象,而且 ...

  8. javascript中各种继承方式的优缺点

    javascript中实现继承的方式有很多种,一般都是通过原型链和构造函数来实现.下面对各种实现方式进行分析,总结各自的优缺点. 一 原型继承 let Super = functioin(name = ...

  9. javascript中实现继承的几种方式

    javascript中实现继承的几种方式 1.借用构造函数实现继承 function Parent1(){ this.name = "parent1" } function Chi ...

随机推荐

  1. C#Redis字符串

    上周六通宵打牌周日白天只睡3小时累成狗,从今天起以后不能玩太大的了,小赌怡情大赌伤身,和同事朋友有空玩玩还是好的.今天公司外面马路上有人挂灯笼时死了一个人,哎,快过年了悲剧又发生了,真是生命是脆弱的. ...

  2. Java反射机制浅析

    概念 Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语 ...

  3. iOS 电商购物车倒计时时间计算

    /** * 倒计时 * * @param endTime 截止的时间戳 * * @return 返回的剩余时间 */ - (NSString*)remainingTimeMethodAction:(l ...

  4. android两种方式获取AsyncTask返回值

    获取AsyncTask返回值,在Activity中使用. 引用链接:https://www.oschina.net/code/snippet_725438_49858#72630 [1].[代码] [ ...

  5. 使用Gradle编译release apk报错:Please correct the above warnings first

    在开发SDK的过程中,遇到了一个研发,使用了自己的SDK之后遇到了各种问题,于是我们自己帮忙接入. 所有代码都接入完成之后,准备export出一个release包,但是此时却报错: 此时出现了很多的w ...

  6. 读书笔记之《The Art of Readable Code》

    <The Art of Readable Code>- Dustin Boswell, Trevor Foucher    O'Reilly出版 整体认知:这本书写得很好,每一章后面的总结 ...

  7. [MFC美化] USkin使用详解-使用方法

    该种皮肤库资料很少,用法与前面几种类似. 它主要有:USkin.dll ,USkin.lib,USkin.h和Sakura.msstyles这四个文件.皮肤格式是.u3.SkinBuilder是USk ...

  8. springIOC

    从这段代码开始 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Pers ...

  9. python流程控制:while循环

    python编程中whihe语句用于循环执行程序,即在某条件下,循环执行某段程序,以处理需要重复处理的相同任务. while循环语句格式: while <判断条件>: 执行语句 count ...

  10. 更改系统相机UIImagePickerController导航栏的cancle为自定义按钮

    有时候需要对系统相册里面的取消按钮进行自定义,并获取点击事件做一些操作,那么你可以这样做. 第一:实现navigationController代理 - (void)navigationControll ...