JavaScript的元系统

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);
1
也可以通过将一般对象的原型置为null来得到一个原子:

var atom = Object.setPrototypeOf(new Object, null);
1
并且,在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';

console.log(isAtom(null));
console.log(isAtom(Object.prototype));
console.log(isAtom(namespace));
在同一个运行环境中,可以并存多个原子,以及由原型指向原子的、原型继承的对象系统。所有这些原子以及衍生的对象系统都是互不相等、没有交集的。

> Object.create(null) === Object.create(null)
false
1
2
因此,JavaScript原生的、由Object()派生或创建的对象、类,在本质上也是上述“对象系统”之一。但是,

作为唯一特例,Object()所属的对象系统称为“原生对象系统”,以区别于后来创建的其它原子对象系统。
并且,

作为唯一特例,null值是一个原子(注:原子在ECMAScript约定的ECMAScript language types中不是对象,但在JavaScript自身的类型检查(typeof)中它是对象)。
NOTE(2018.08.28): 修正了一处关于arguments的错误,确认arguments对象不是原子。thanks for hebaby @github

元(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 {};
}
1
2
3
当然,由于在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
--------------------- 
原文:https://blog.csdn.net/aimingoo/article/details/82014291 

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页