彻底理解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. [置顶] Objective-C ,ios,iphone开发基础:ios数据库(The SQLite Database),使用终端进行简单的数据库操作

    SQLite  是一个轻量级的免费关系数据库.SQLite最初的设计目标是用于嵌入式系统,它占用资源非常少,在嵌入式设备中,只需要几百K的内存就够了,可以在(http://www.sqlite.org ...

  2. 与众不同 windows phone (15) - Media(媒体)之后台播放音频

    原文:与众不同 windows phone (15) - Media(媒体)之后台播放音频 [索引页][源码下载] 与众不同 windows phone (15) - Media(媒体)之后台播放音频 ...

  3. 与众不同 windows phone (2) - Control(控件)

    原文:与众不同 windows phone (2) - Control(控件) [索引页][源码下载] 与众不同 windows phone (2) - Control(控件) 作者:webabcd介 ...

  4. 14.5.5 Creating a File-Per-Table Tablespace Outside the Data Directory

    14.5.5 Creating a File-Per-Table Tablespace Outside the Data Directory 创建一个File-Per-Table Tablespace ...

  5. python random模块 - 小驹的专栏 - 博客频道 - CSDN.NET

    python random模块 - 小驹的专栏 - 博客频道 - CSDN.NET python random模块 分类: python 2011-11-15 15:31 6037人阅读 评论(2) ...

  6. [置顶] ※数据结构※→☆线性表结构(queue)☆============优先队列 链式存储结构(queue priority list)(十二)

    优先队列(priority queue) 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除.在优先队列中,元素被赋予优先级.当访问元素时,具有最高优先级的元素最先删除.优先队列具有 ...

  7. Java设计模式之适配器模式(Adapter Pattern)

    Adapter Pattern的作用是在不改变功能的前提下转换接口.Adapter分为两类,一类是Object Adapter, 还有一类是Class Adapter.因为Class Adapter的 ...

  8. [iOS]简单的APP引导页的实现 (Swift)

    在第一次打开APP或者APP更新后通常用引导页来展示产品特性 我们用NSUserDefaults类来判断程序是不是第一次启动或是否更新,在AppDelegate.swift中加入以下代码: func ...

  9. 文档数据库RavenDB-介绍与初体验

    文档数据库RavenDB-介绍与初体验 阅读目录 1.RavenDB概述与特性 2.RavenDB安装 3.C#开发初体验 4.RavenDB资源 不知不觉,“.NET平台开源项目速览“系列文章已经1 ...

  10. 虚继承之单继承的内存布局(VC在编译时会把vfptr放到类的头部,这和Delphi完全一致)

    C++2.0以后全面支持虚函数与虚继承,这两个特性的引入为C++增强了不少功能,也引入了不少烦恼.虚函数与虚继承有哪些特性,今天就不记录了,如果能搞了解一下编译器是如何实现虚函数和虚继承,它们在类的内 ...