如何用JavaScript实现ECMA-262 §7.2.8定义的IsRegExp抽象操作?
JavaScript抽象操作IsRegExp的实现探讨
ECMA-262标准定义了抽象操作IsRegExp,用于判断对象是否应被视为正则表达式对象,其规范步骤如下:
IsRegExp抽象操作接收一个参数,返回布尔值表示该对象是否为正则表达式对象,执行步骤为:
- 若参数不是对象,返回false;
- 令matcher为?Get(argument, @@match);
- 若matcher不为undefined,返回ToBoolean(matcher);
- 若参数拥有[[RegExpMatcher]]内部槽,返回true;
- 返回false。
——ECMA-262 §7.2.8 IsRegExp
比如"haystack".search(needle)就会通过这个操作判断needle是否按正则处理。目前没有直接暴露的API仅执行该操作,我们可以实现大部分逻辑,但步骤4无法直接通过普通代码完成:
function IsRegExp(x) { // step 1 if (typeof x !== "object" || x === null) return false; // steps 2 and 3 if (Symbol.match in x) return !!x[Symbol.match]; // step 4 ??? // step 5 return false; }
核心疑问解答
能否用普通JavaScript代码实现步骤4?
不能直接实现。因为[[RegExpMatcher]]是JavaScript引擎的内部槽,没有对外暴露的API可以直接检测对象是否拥有这个槽,必须通过利用内置方法的语义间接判断。如何模拟完整的IsRegExp操作?
可以利用String.prototype.search的内部逻辑来间接实现完整的IsRegExp判断,因为search会严格按照IsRegExp的步骤处理参数。实现代码如下:
function isRegExp(x) { // 步骤1:非对象直接返回false if (typeof x !== 'object' || x === null) return false; // 步骤2-3:检查Symbol.match属性 if (Symbol.match in x) { return !!x[Symbol.match]; } // 步骤4:间接检测[[RegExpMatcher]]内部槽 try { // 临时替换toString方法,若x被当作非正则处理,new RegExp(x)会调用toString并抛出错误 const originalToString = x.toString; x.toString = () => { throw new Error(); }; // 调用search,若x是正则则不会触发toString,不会报错 ''.search(x); // 恢复原toString方法 x.toString = originalToString; return true; } catch (e) { // 报错说明x被当作非正则处理,没有[[RegExpMatcher]] return false; } }
- 典型使用场景
比如实现一个自动将输入转为正则的工具函数:
function ensureRegExp(x) { return isRegExp(x) ? x : new RegExp(x, "u"); }
内容的提问来源于stack exchange,提问作者zwol
相关产品推荐
相关产品推荐

