彻底理解Javascript原型继承

之前写过一篇Javascript继承主题的文章,这篇文章作为一篇读书笔记,分析的不够深入。

本文试图进一步思考,争取彻底理解Javascript继承原理

实例成员与原型成员

举一个《高性能Javascript》书中例子

var book={
title :"High Performance JavaScript",
publisher:"Yahoo!Press"
};
alert(book.toString());//"[object Object]"

Javascript对象有两种类型的成员:实例成员和原型成员。实例成员存在于实例自身,原型成员则从对象的原型继承

上述示例中,book对象有两个实例成员:title和publisher。book对象并没有定义toString()方法,但是却可以调用这一方法,这是因为toString()方法是book对象继承的一个原型成员

book示例成员与原型成员关系如下图。当book.toString()被调用时,首先从对象实例搜索toString方法,如果没有找到,就转向搜索原型对象。通过这种方式,book可以访问他的原型所有的属性和方法。

原型模式创建对象

function Person(){}
Person.prototype.name="Nicholas";
Person.prototype.age=29;
Person.prototype.job="Software Engineer";
Person.prototype.sayName=function(){alert(this.name)}; var person1=new Person();
person1.sayName();//"Nicholas" var person2=new Person();
person2.sayName();//"Nicholas"

上述代码中,Person构造函数、原型对象和实例对象见关系如下

将Person属性成员不再定义在原型对象上时

function Person(name)
{
this.name=name;
}
Person.prototype.sayName=function(){alert(this.name)};
var p1=new Person("Zhangsan");

上述代码中,Person构造函数、原型对象和实例对象关系如下图所示

从上面两图可以看出,当属性定义在构造函数中时,属性成员存在于实例对象中;属性定义在原型对象中时,实例对象访问这一属性,需要沿原型链查找该属性

原型链继承

让构造函数的原型对象等于另一个类型的实例,利用原型让一个引用类型继承另一个引用类型的属性和方法

function SuperType()
{
this.property=true;
}
SuperType.prototype.getSuperValue=function(){
return this.property;
};
function SubType()
{
this.subProperty=false;
}
//继承SuperType
SubType.prototype=new SuperType();
SubType.prototype.getSubValue=function(){
return this.subProperty;
} var instance=new SubType();
alert(instance.getSuperValue());//true

代码示例中,完整原型链如下

图中值得注意的细节是,父类SuperType的属性property存在于SuperType的实例对象中,getSuperValue方法存在于其原型对象中

将SuperType实例对象赋给子类SubType的原型对象后,SubType原型对象prototype获得了父类的property属性

换一种写法行不行?

上文是通过将父类的实例对象赋给子类的原型对象,实现了继承的效果

直接将父类的原型对象赋给子类的原型对象行不行?

function Super()
{
this.attr='a';
}
Super.prototype.func=function(){alert('Super');}; function Sub()
{
this.x='1';
} Sub.prototype =Super.prototype; Sub.prototype.test=function(){alert('Sub');} var sub=new Sub();
sub.func();//'Super'
sub.test();//'Sub' sub.attr;//undefined
sub.x;//

上述代码中,将Super.prototype直接赋给Sub.prototpye,发现对Sub类型实例对象sub,访问attr属性时,无法获取

这就是因为attr属性定义在Super构造函数中,而不是定义在Super的原型对象上,此时Super.prototype中并没有attr属性

假设将Super所有属性都定义在原型对象上,如下所示,这时sub实例对象是可以访问到父类的attr属性的

但这时,Super类所有实例对象,都共享了attr属性,一个实例对attr属性的更改,会引起其他实例对象attr属性值的变更,这是应该避免的

function Super()
{
}
Super.prototype.attr='a';
Super.prototype.func=function(){alert('Super');}; function Sub()
{
this.x='1';
} Sub.prototype =Super.prototype; Sub.prototype.test=function(){alert('Sub');} var sub=new Sub(); sub.attr;//a
sub.x;//

再换一种写法看看

function Super()
{
this.attr='a';
}
Super.prototype.func=function(){alert('Super');}; function Sub()
{
this.x='1';
} Sub.prototype =Super(); Sub.prototype.test=function(){alert('Sub');} var sub=new Sub();
sub.func();
sub.test(); sub.attr;
sub.x;

实际上,上面代码会直接报错,提示test属性没有被定义

原因是Sub.prototype=Super();这句代码,实际上是将Sub.prototype指向了undefined,因为Super()语句,是在以函数行驶调用Super()方法,这一调用,是没有返回值的

经过这一调用,Sub.prototype此时已经为undefined,再为他定义test属性,自然就报错了

彻底理解Javascript原型继承的更多相关文章

  1. 深入理解javascript原型和闭包(6)——继承

    为何用“继承”为标题,而不用“原型链”? 原型链如果解释清楚了很容易理解,不会与常用的java/C#产生混淆.而“继承”确实常用面向对象语言中最基本的概念,但是java中的继承与javascript中 ...

  2. 深入理解javascript原型和闭包 (转)

    该教程绕开了javascript的一些基本的语法知识,直接讲解javascript中最难理解的两个部分,也是和其他主流面向对象语言区别最大的两个部分--原型和闭包,当然,肯定少不了原型链和作用域链.帮 ...

  3. 深入理解javascript原型和闭包系列

    从下面目录中可以看到,本系列有16篇文章,外加两篇后补的,一共18篇文章.写了半个月,从9月17号开始写的.每篇文章更新时,读者的反馈还是可以的,虽然不至于上头条,但是也算是中规中矩,有看的人,也有评 ...

  4. 深入理解javascript原型和闭包(5)——instanceof

    又介绍一个老朋友——instanceof. 对于值类型,你可以通过typeof判断,string/number/boolean都很清楚,但是typeof在判断到引用类型的时候,返回值只有object/ ...

  5. 深入理解javascript原型和闭包(7)——原型的灵活性

    在Java和C#中,你可以简单的理解class是一个模子,对象就是被这个模子压出来的一批一批月饼(中秋节刚过完).压个啥样,就得是个啥样,不能随便动,动一动就坏了. 而在javascript中,就没有 ...

  6. 深入理解javascript原型和闭包(完结)

    原文链接:http://www.cnblogs.com/wangfupeng1988/p/3977924.html 说明: 该教程绕开了javascript的一些基本的语法知识,直接讲解javascr ...

  7. 深入理解javascript原型和闭包

    目录: 深入理解javascript原型和闭包(1)——一切都是对象 深入理解javascript原型和闭包(2)——函数和对象的关系 深入理解javascript原型和闭包(3)——prototyp ...

  8. 《深入理解javascript原型和闭包系列》 知识点整理(转)

    深入理解javascript原型和闭包系列 对原型和闭包等相关知识的讲解,由浅入深,通俗易懂,每个字都值得细细研究. 一.一切都是对象 1. typeof操作符输出6种类型:string boolea ...

  9. 《深入理解javascript原型和闭包系列》 知识点整理

    深入理解javascript原型和闭包系列 对原型和闭包等相关知识的讲解,由浅入深,通俗易懂,每个字都值得细细研究. 一.一切都是对象 1. typeof操作符输出6种类型:string boolea ...

随机推荐

  1. meta viewport标签的使用说明(手机浏览缩放控制)

    网页中有这么一句时,在iPhone的浏览器中将以原始大小显示,并不允许缩放. <meta name="viewport" content="width=device ...

  2. 谈谈Ext JS的组件——布局的用法续二

    绝对布局(Ext.layout.container.Absolute) 绝对布局让我回忆到了使用Foxpro开发的时候,哪时候的界面布局就是这样.通过设置控件的左上角坐标(x.y)和宽度来进行的,由于 ...

  3. [知识库分享系列] 二、Web(高性能Web站点建设)

    知识库分享系列: [知识库分享系列] 二..NET(ASP.NET) [知识库分享系列] 一.开篇 分享介绍 此知识库之所以为 Web 系列,因为和 .NET 没有完全的关系,其中的技术和实践实用于各 ...

  4. ALV双击单元格事件处理

    *激发双击事件 FORM f_alv_user_command USING r_ucomm LIKE sy-ucomm rs_selfield TYPE slis_selfield. "先引 ...

  5. 旧版QT的名称:qt-win-commercial-4.4.3-vc60.exe

    qt-win-commercial-4.4.3-vc60.exeqt-vsaddin-collection-2.1.4.exeqt-win-commercial-4.4.3-v2005.exeqt-v ...

  6. hdu 4277

    题目链接 #include <cstdio> //by-ACMer_xiaohao #include <cstring> #include <map> using ...

  7. Android studio ElasticDownloadView

    找到个开源项目,地址:https://github.com/Tibolte/ElasticDownload 下载进度效果: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkb ...

  8. Java方法区和运行时常量池溢出问题分析(转)

    运行时常量池是方法区的一部分,方法区用于存放Class的相关信息,如类名.访问修饰符.常量池.字段描述.方法描述等. String.intern()是一个native方法,它的作用是:如果字符串常量池 ...

  9. pv操作 生产者消费者

    #include <iostream> #include <stdlib.h> #include <pthread.h> #include <semaphor ...

  10. Eclipse Tips

    一.取消拼写检查 Window -> Preferences -> General -> Editors -> Text Editors -> Spelling -> ...