background image

自省机制

需要编程实现,

MFC 实现的

RTTI

Js 中的对象即关联数组

动态

/静态

静态语言

动态语言

动态语言的意思就是代码可以
在运行时修改自身。

面向对象

Class

Function.prototype。

基于原型的继承

面向对象

对象是

class

的实例

对象其实是个关联数组。

 

函数式语言

JS 实现了

函数式

的编程泛型(

programming paradigm),其中一个重要的特点是,

函数是第一层次的数据类型

,是和整数、浮点数、字符串这些类型处于同一层次。可以定义类

型为函数的变量,并且可以进行一些特定的运算。类型是函数的变量和

C 语言里面函数指针

的差别是:函数指针是一个地址,是没有上下文的,而函数变量是一个对象,包含了运行
的上下文。

 

函数作为第一层次的数据类型,是后面通过原型继承实现面向对象的关键点之一。 没

有了这个机制,就无法仅仅赋值关联数组构造真正意义上的类(包含了数据和操作)。
 

面向对象

面向对象在很多领域并不是非常必要的,比如说单纯的数据处理。

即使是写

操作系统内核这种繁重的工作,依然可以使用面向过程很好地完成。但是,面向对象从出现
到现在,其最重要的应用领域恐怕是

GUI 了(复杂的对象关系、交互、消息、异步性导致了

复杂的逻辑)。而

Web 应用的

富浏览器化

导致了将使用

js 进行面向对象编程变得重要,因

为浏览器端的交互越来越像客户端。

JS 的面向对象

C++里面不同,没有提供像 class 和 struct 这种定义类型的关键

字,而是使用了

Function 的

prototype

通过原型继承来实现的。这里

prototype 可以理解为

JS 的一个特殊的关联数组

。类的构造是通过关联数组域的定义完成,类的封装是通过关联

数组的封装性来实现,而类的继承都是通过关联数组的复制来完成的。(其中用原型实现类
继承相当于是在语言层次上实现了设计模式中的原型模式。关于原型模式详情可以参考

GoF

的《设计模式》。)

什么是

new

JS 的 new 相当于

复制

一个关联数组的

prototype 属性从而生成新的数组,并

执行

造函数的过程。

为什么要基于原型继承?

我的观点是,

JS 的作者为了

实现纯粹的弱类型

。因为无论是

struct 和 class 都是在

定义一个类型,将这些东西引入语言中。就使得

JS 内建的类型和用户自定义类型的使用上

存在本质的差别。一个是隐式指定类型,一个要显式指定类型。

而基于这种

prototype 的类继承,其过程事实上仅仅是对象的拷贝,并不涉及到显

式类型的定义。

但是,并非所有脚本语言都是这样设计的,其他一些脚本语言如

python、ruby 等,

还是利用了明显的

class 关键字来定义类。

为 什 么 要 有 一 个

prototype 属 性 , 而 不 是 直 接 任 意 关 联 数 组 都 能

new

Prototype 相当于用户和 JS 运行环境约定的定义类型的关键字,如果所有的关联数

组都能

new,那么那些不需要实现成类的数据类型的关联数组就要付出

额外的开销

。(这里

可以对比

C++中纯数据 struct 和包含了构造函数的 struct 的区别)。

所以,

prototype 可以认为是执行环境和 JS 语言的约定:叫这个名字的关联数组才

进行复制。

 

自省机制、动态语言及元编程

元编程

简单来说就是用

程序生成程序