两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客:

理解JavaScript中原型继承

JavaScript中的原型继承

这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误理解。今天看《Understanding Scopes》这让我从新思考了一下原型继承,更重要的是站在一个继承设计者的角度再看一下原型继承。

在传统的面向类的继承体系中,我们有个Best Practices是优先使用(对象)组合代替(类)继承,而原型继承是这个思想的一个运用。和面向对象和函数式编程一样,使用几乎任何语言都可以实现这样的思想,我以前学的只是这个思想的一个JavaScript实现,而已。

基于原型的继承其实是一种组合式的继承,朴素的说法就是子域中属性找不到的话就去父域中找找,这里的父域是用原型(__proto__)去引用的,依次递归整个原型链。最终的实现其实就是对象的组合。子对象包含父对象的引用。既然是继承必然涉及到重名问题,子对象和父对象各自相当于一个作用域,重名问题的处理也是就近(可覆盖shadow/隐藏hide)原则,即子作用域的同名属性会起作用,隐藏了父作用域的同名属性,但是由于是组合,这两个属性是独立的。我们用伪代码看看:

aParent = {name:’jerry’}

aChild = {__proto__:aParent, name:’frank’}

aChild中的name和aParent中的name是各自独立的。我们aChild.name=’unknown’并不会改变aParent.name。

有一点要拿出单独说说,造成迷糊的最大根源就是误解,对于如下代码:

aParent = {name:’jerry’}

aChild = {__proto__:aParent}

若我们取aChild.name的值,我们很容易resolve,那就是子域中找不到,去父域中找,找到了jerry。但是对于:aChild.name = ‘frank’这样的赋值代码我们会产生歧义(ambiguous),我们可能有两中含义:

1,更新父域中的name属性为frank。

2,设置子域中的name属性为frank。

JavaScript选用的方式是第2种。即设置(新建)子域自己的name属性为frank,并隐藏了父域中的name属性。我们通常误以为JavaScript是按1的方式工作,其实不是。

另外类(模版)其实在编程语言的实现中是可有可无的,像JavaScript压根就没有类(模版),他只有对象,new Point()只不过是一个语法糖,跟aObj = createObject()是一样的,只是调用一个方法去生成一个对象,而已。

理解JavaScript中的原型继承(2)的更多相关文章

  1. javascript中的原型继承

    在Javascript面向对象编程中,原型继承不仅是一个重点也是一个不容易掌握的点.在本文中,我们将对Javascript中的原型继承进行一些探索. 基本形式 我们先来看下面一段代码: <cod ...

  2. 理解javascript中的原型模式

    一.为什么要用原型模式. 早期采用工厂模式或构造函数模式的缺点:  1.工厂模式:函数creatPerson根据接受的参数来构建一个包含所有必要信息的person对象,这个函数可以被无数次的调用,工厂 ...

  3. 如何理解JavaScript中的原型和原型链

    首先是一张关系图,避免抽象化理解时产生的困难 Function对象 函数对象是JavaScript学习中不可避免的一部分,而且这一部分相对重要且抽象 函数的创建方式有2种: 字面量创建 var foo ...

  4. javascript 中的原型继承

    javascript圆形变成的基本规则: 所有数据都是对象: 要得到一个对象,不是通过实例化类,而是找到一个对象作为原型并克隆它: 对象会记住它的原型: 如果对象无法响应某个请求,它会把这个请求委托给 ...

  5. 简单理解javascript中的原型对象,实现对之间共享属性和行为

    javascript中提供了构造函数.可以方便的创建对象. 典型的构造函数例如以下: function Person(name, age) { this.name = name; this.age = ...

  6. 深入理解JavaScript中的类继承

    由于写本文时全部是在编辑器中边写代码边写感想的,所以,全部思想都写在代码注释里面了 // 类继承 //todo.1 extends 关键字 class Animal { constructor(nam ...

  7. JavaScript中的原型继承原理

    在JavaScript当中,对象A如果要继承对象B的属性和方法,那么只要将对象B放到对象A的原型链上即可.而某个对象的原型链,就是由该对象开始,通过__proto__属性连接起来的一串对象.__pro ...

  8. Javascript中的原型继承具体解释

    js中的继承,是面向对象的知识,由于js没有类的概念.所以继承是通过对象实现的.谈到继承.就必须说到prototype,就不得不先说下new的过程. 一个小小的列子: <script type= ...

  9. 一句话简单理解javascript中的原型对象

    通过构造函数F创建的对象实例p 这个对象p的原型对象是 构造函数中prototype属性指向的对象s,这个对象p中也有个非标准的__proto__属性指向构造函数prototype属性所指向的对象s, ...

随机推荐

  1. Android的px、dp和sp

    Android的px.dp和sppx: 即像素,1px代表屏幕上一个物理的像素点:偶尔用到px的情况,是需要画1像素表格线或阴影线的时候. dp: 这个是最常用但也最难理解的尺寸单位.它与“像素密度” ...

  2. datatable删除行

    先列出正确的写法,如果你只想马上改错就先复制吧, protected void deleteDataRow(int RowID,DataTable dt) { ; i >= ; i--) { i ...

  3. 不需要写代码,文件夹右键cmd定位指定目录

    引子 这篇文章其实本来不是这样的,因为我用C#的代码实现了一个程序,后面才突然发现,我太傻太天真了,明明不需要写程序和写代码的,结果自己把自己二住了. 我们来看看效果图. 由于,我自己的原因,这个功能 ...

  4. Java的List排序

    有时需要对List排序,这时可以利用Collections的sort()方法来排序,不用自己再去排序. package myTest; import java.util.ArrayList; impo ...

  5. SSH服务器与Android通信(1)--服务器端发送数据

    很多应用要求SSH服务器不仅和PC通信,还要和Android移动设备通信,这时就需要用到JSON了.其基本原理是服务器将数据转换成JSON格式,发送给Android客户端,客户端再将JSON格式的数据 ...

  6. 关于【error C3646: 未知重写说明符】的若干种可能性

    如果在程序中出现了error C3646,那么这个错误可能是由多种问题所导致的,这篇文章将对多种错误及对应解决方法进行分析. 在MSDN的官方网站中,Complier Error C3646的定义为u ...

  7. Scalaz(18)- Monad: ReaderWriterState-可以是一种简单的编程语言

    说道FP,我们马上会联想到Monad.我们说过Monad的代表函数flatMap可以把两个运算F[A],F[B]连续起来,这样就可以从程序的意义上形成一种串型的流程(workflow).更直白的讲法是 ...

  8. Scalaz(8)- typeclass:Monoid and Foldable

    Monoid是种最简单的typeclass类型.我们先看看scalaz的Monoid typeclass定义:scalaz/Monoid.scala trait Monoid[F] extends S ...

  9. Java.io.DataInputStream.readInt()

    1. 代码 import java.io.DataInputStream; import java.io.IOException; public class Test { public static ...

  10. MyEclipse10 中的两种FreeMarker插件的安装与配置

    第一个插件是:                                       freemarker-ide MyEclipce10.0中安装FreeMarker插件,这绝对是最简单的方法 ...