自省机制
需要编程实现,
如
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 语言的约定:叫这个名字的关联数组才
进行复制。
自省机制、动态语言及元编程
元编程
简单来说就是用
程序生成程序
。