让 JerryScript 支持 "operator[](int)" 重载
背景
在 C++ 中,当我们想用下标访问对象中的第 i 个元素时,可以重载下标运算符(subscript operator)。但是 JavaScript(ECMAScript 5.1)中并没有类似的机制,如果我们想访问第 i 个元素,必须添加一个名为 ToString(i)
的属性;如果想访问元素 1 .. n ,就必须添加 n 个属性。显然这种做法存在额外的内存开销,在嵌入式硬件上是不可接受的。
思路
为了解决上述问题,一个很自然的想法就是对 ECMA 的 [[Get]]
1 和 [[Put]]
2 进行扩展:
- 当属性
P
未找到时,令I = ToNumber(P)
。 - 若
I
为整数,则查找__get_by_index__
/__put_by_index__
方法。 - 若找到,则返回
__get_by_index__(I)
/__put_by_index__(I, V)
。
实现
JerryScript 引擎的 [[Get]]
和 [[Put]]
实现位于 “ecma-objects.c”,本文限于篇幅不贴具体代码,大家只要在注释处按照上节的讨论编写即可,留作练习。
ecma_value_t
ecma_op_object_get (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p) /**< property name */
{
......
do {
......
}
while (object_p != NULL);
{
// Implement our [[GET]] extension right here.
}
......
}
ecma_value_t
ecma_op_object_put (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p, /**< property name */
ecma_value_t value, /**< ecma value */
bool is_throw) /**< flag that controls failure handling */
{
......
ecma_property_t *property_p = ecma_find_named_property (object_p, property_name_p);
......
if (property_p == NULL)))
{
{
// Implement our [[PUT]] extension right here.
}
if (type == ECMA_OBJECT_TYPE_STRING)
{
......
}
......
}
......
}
测试
将 JerryScript 重新编译后,我们可以使用以下代码进行验证:
function Box() {
}
Box.prototype.__get_by_index__ = function (i) {
print('get:', i);
return i;
};
Box.prototype.__put_by_index__ = function (i, value) {
print('put:', i, value);
return value;
};
var box = new Box();
for (var i = 0; i < 10; ++i) {
assert(box[i] === i);
}
for (var i = 0; i < 10; ++i) {
assert((box[i] = i) === i);
}
大功告成~