JavaScript的元系统
栏目: JavaScript · 发布时间: 6年前
内容简介:本文是对在第四届FEDay中分享的《无类继承:JavaScript面向对象的根基》的进一步讨论。也是对开源项目ECMAScript中只有两处提及到“Meta”这个概念,一处是说明ECMAScript的规范类型(所以ECMAScript中是没有所谓“元系统(
本文是对在第四届FEDay中分享的《无类继承:JavaScript面向对象的根基》的进一步讨论。也是对开源项目 @aimingoo/metameta 的解析。
ECMAScript中只有两处提及到“Meta”这个概念,一处是说明ECMAScript的规范类型( a specification type
)是用于描述和实现语言类型( language types
)的元值( meta-values
),另一处则是唯一被称为“元属性( Meta Property
)”的 new.target
。
所以ECMAScript中是没有所谓“元系统( Meta system )”或“元类型系统( Meta type system )”。我们在这里先定义一个称为“原子( Atom )”的东西,并基于此来构建起一个完整的JavaScript元系统。
原子(atom)
定义:原子是JavaScript中的对象的最小单元,它是对象但不继承自Object();以原子为原型的对象也会被称为原子对象。
JavaScript中的对象就是一个属性包( properties bag, or a collection of properties ),一个属性包为空集时,它必然是对象的最小形态。因此一个没有原型,且自有属性集为空的对象,必然是一个原子。
原子可以用ES5兼容的语法创建出来:
var atom = Object.create(null);
也可以通过将一般对象的原型置为null来得到一个原子:
var atom = Object.setPrototypeOf(new Object, null);
并且,在ECMAScript中有四个内建/原生对象是原子的:
function isAtom(x) { switch (typeof x) { case 'object': case 'function': return !(x instanceof Object); } return false; } // modules in es6 import * as namespace from './your-module.js'; // arguments from function var args = Function('return arguments')(); console.log(isAtom(null)); console.log(isAtom(Object.prototype)); console.log(isAtom(namespace)); console.log(isAtom(args));
在同一个运行环境中,可以并存多个原子,以及由原型指向原子的、原型继承的对象系统。所有这些原子以及衍生的对象系统都是互不相等、没有交集的。
> Object.create(null) === Object.create(null) false
因此,JavaScript原生的、由Object()派生或创建的对象、类,在本质上也是上述“对象系统”之一。但是,
- 作为唯一特例,Object()所属的对象系统称为“原生对象系统”,以区别于后来创建的其它原子对象系统。
并且,
- 作为唯一特例,null值是一个原子(注:原子在ECMAScript约定的ECMAScript language types中不是对象,但在JavaScript自身的类型检查( typeof )中它是对象)。
元(meta)
定义:能产生原子(atom)的一个过程称为元(meta)。
推论:原子的构造器(Atom)与元(meta)是等义的。
由于atom对象的构造器通常记为Atom(),所以从概念上它与“元(meta)”是等义的,在实际使用中我们也并不明确地区分二者。
meta可以是一个函数,也可以是一个类,甚至也可以是一个代理对象( proxy )、箭头函数( arrow functions )或方法( methods )。——在概念定义中,我们只约定了“meta是一个过程”,并没有强调atom是它构建出来的,亦或只是它的调用结果。
在开源项目中Metameta( @aimingoo/metameta )中,meta是以ES6的语法声明的一个Atom类:
class Atom extends null { constructor() { return Object.create(new.target.prototype); } }
任何情况下,我们用该meta都可以产生新的原子对象:
> isAtom(new Atom) true > new Atom === new Atom false
元类型(Meta,Meta types)
定义:所有元(meta)的类型称为元类型(Meta types)
在JavaScript中,一个数据所对应的类型可以用它的构造器来标示,亦即是Meta();并且这也意味着Meta()作为构造器产生的实例是元( meta )。亦即是说,Meta()应当是一个“返回meta过程”的过程。
在ES6的语法中,可以简单地在函数中返回一个“类声明( class definitions )”来得到一个字面量风格的类。因此在Metameta中声明了MetaMeta()类来作为元类型的祖先类:
// Meta's super class MetaMeta extends null { constructor(base) { // Atom() by default return Object.setPrototypeOf(class extends new.target {}, base); } ...
所以现在,我们就可以通过如下的方法来得到一个原子了:
// Atom与meta是同义的 > Atom = meta = new MetaMeta // 创建一个原子 > atom = new Atom // 检测 > isAtom(atom) true
基于原子的继承性
我们之所以要用class来声明Atom和MetaMeta,是为了简单地得到面向对象的继承性。亦即是说,当我们想要派生一个新的原子对象类型的时候,可以简单地通过扩展上述的系统来得到它的构造器。例如:
class MyAtomObject extends new MetaMeta { get description() { return 'i am an atom.'; } } var x = new MyAtomObject; console.log(x.description);
在这个例子中, new MetaMeta
直接创建了一个Atom,而 MyAtomObject
则派生自该Atom,因此它的实例自然是atom。并且,基于ES6的类声明语法, MyAtomObject
也可以具有自己的存取器成员、对象方法,或者类方法。
基于元的继承性
从MetaMeta也可以基于元类型进行派生,由此我们可以实现“元类(Meta class)类型”。
定义:元类(Meta class)是一个产生类(class)的过程。
从定义上来说,简单的元类可以写成:
function SimpleMetaClass() { return class {}; }
当然,由于在MetaMeta中“元类型”本身就是基于类实现的——亦即是它本来就是一个“返回类”的过程,因此它只需要简单的一层概念抽象就可以实现“元类”类型了。如下:
// “元(Meta)”类型 class Meta extends MetaMeta { ... } // “元类(MetaClass)”类型 class MetaClass extends Meta { ... }
之所以让Meta派生自MetaMeta(),主要目的是为了得到一层super声明,以确保Meta()以及它的类方法( static methods
)之于它的super是词法上下文绑定的。而“元类(MetaClass)”则用于派生一层类型声明,以便让MetaClass()能拥有自己的类方法,例如 MetaClass.isClassOf()
。
现在,我们已经在Meta上实现了一层派生,我们也可以实现更多层的派生,以通过“类类型”的方法来得到更多的构造器——换言之,我们可以产生更多的类,它们都可以作为更多的“不同的对象系统的”祖先类。我们可以让JavaScript中出现多个完全不同的、与Object()所代表的“原生对象系统”并列的对象系统。
如前所述的——它们相互独立,没有交集。例如:
// “元类(MetaClass)”产生类 var ObjectEx = new MetaClass; // 基于ObjectEx可以派生一个“独立的、不同的”对象系统 class MyObjectEx extends ObjectEx {}; // 可以用类似的方法来派生更多这样的对象系统 class MyObjectPlus extends new MetaClass { ... };
接下来,你可以检测它们的类属关系:
> ObjectEx.isClassOf(MyObjectEx) true > MetaClass.isClassOf(ObjectEx) true
或使用ECMAScript内置方法检测原子:
> (new MyObjectEx) instanceof ObjectEx true > (new MyObjectEx) instanceof MyObjectPlus false
以上所述就是小编给大家介绍的《JavaScript的元系统》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 告警系统主脚本,告警系统配置文件,告警系统监控项目
- 分布式系统的那些事儿(三) - 系统与系统之间的调用
- 在线考试系统从Windows系统迁移到Linux系统的整个过程
- 系统设计之系统建设的目的
- 文件系统(二)fastdfs和其他文件系统区别
- 分布式系统-->(关于系统应用的基本概念)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。