Web IDL 简介

前言

最近研究 Chromium 和 HTML 标准,不可避免的就接触到了 Web IDL,这里就总结性的聊聊吧,也当是学习笔记了。

本文几乎就是照搬现在 Web IDL 的标准,但也不是简单的翻译也翻译不准

简介

Web IDL 全称 Web Interface Definition Language。现在 Web IDL 只有第一版,是 W3C 2016 年出的,然而现在几乎没有人用它,大家用的都是还在草案阶段的第二版。这里忍不住道一点题外话,之前 W3C 和 WHATWG 闹掰,W3C 的想法是在积累一定的 Fix 后就固定版本而 WHATWG 希望是对标准不断修补,结果 HTML5 标准一直有两个,直到今年 5 月底 W3C 和 WHATWG 才宣布共同维护一个标准。而在 Web IDL 第二版草案成为实质标准的现在可以看出,搞个固定的版本明显是没人喜欢用的,大家还是喜欢最新的标准,像以前 HTML1 - HTML4 那种一个版本一个脚印的时代已经不存在了,不太理解 W3C 的想法。

说回正题,那么为什么需要 Web IDL?首先在 Web IDL 之前已经有一种类似的语言叫做 OMGIDL 用来定义 W3C 各个标准中的各种对象,然而由于 ECMAScript 定义并不够精确所以在互相操作和使用的过程中出现了问题,并且每个标准总是在用 OMGIDL 重复描述一些常见的对象造成了冗余,为了解决这些问题就有了 Web IDL。所以 Web IDL 的主要目标是

  • 精确定义浏览器内部各种接口
  • 严谨定义 ECMAScript 和 Web IDL 的绑定

围绕着这两方面,Web IDL 的标准主要有两部分:Interface definition language 和 ECMAScript bindings。

IDL

Identifier

Web IDL 的标识符很简单,稍微特殊一点的是,一般的属性标识符应该避免以下划线开头因为以下划线开头的标识符是保留标识符,而且标识符开头的下划线会被移除。这样说有点抽象,不如看个例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Typedef identifier: "number"
typedef double number;

// Interface identifier: "System"
[Exposed=Window]
interface System {

// Operation identifier: "createObject"
// Operation argument identifier: "interface"
object createObject(DOMString _interface);

// Operation argument identifier: "interface"
sequence<object> getObjects(DOMString interface);

// Operation has no identifier; it declares a getter.
getter DOMString (DOMString keyName);
};

// Interface identifier: "TextField"
[Exposed=Window]
interface TextField {

// Attribute identifier: "const"
attribute boolean _const;

// Attribute identifier: "value"
attribute DOMString? _value;
};

这里最后的 _const 实际标识符是 const_value 也是同理。

Interface

基础语法

最重要的就是接口了,Web IDL 的接口语法和 Java 稍微有些类似,语法很简单。

1
2
3
4
[extended_attributes]
interface identifier {
/* interface_members... */
};

Partial interface

这里 interface 还支持 partial interface,熟悉 C# 的 partial class 应该就马上理解了,实际上就是把一个类的定义分开写,不过文档里面提到这个特性只是为了方便书写标准设计的,实现并不一定使用。比如

1
2
3
4
5
6
7
interface SomeInterface {
/* interface_members... */
};

partial interface SomeInterface {
/* interface_members... */
};

Mixin interface

类似的 interface 还支持 Mixin 模式。Mixin 模式有点类似 Python 的 Duck typing,就是 OOP 中 I can 的表示方法,比如

1
2
3
4
5
6
7
8
9
10
11
12
13
interface Entry {
readonly attribute unsigned short entryType;
// ...
};

interface mixin Observable {
void addEventListener(DOMString type,
EventListener listener,
boolean useCapture);
// ...
};

Entry includes Observable;

这里 Entry 就包含了 Observable。

同样的 Mixin 模式也是为了方便标准的书写,并不要求在实现中使用。

Inherit

同时既然有 Mixin 自然要提到的就是继承,在 Web IDL 中 interface 是支持单继承的,不支持多继承,语法如下

1
2
3
interface identifier : identifier_of_inherited_interface {
/* interface_members... */
};

有意思的是,对于 ECMAScript 来说是没有继承概念的,有的只是原型链,因此标准之规定了如果有同名属性访问的是子类的属性而父类是否能访问需要看具体实现(至少 ECMAScript 是可以的啦)。

Callback interface

实际上一个 Callback interface 并不是一个 interface,这里名称问题是历史遗留问题。它的语法是

1
2
3
callback interface identifier {
/* interface_members... */
};

一个 callback interface 只能有一个 regular operation,简单来说就是一个 method。

另外标准中也提到除非是描述已有的 API,不然应该用 callback function,具体的后面再说。

Members

(未完待续)