返回

Sizzle引擎如何支持更多字符集?

前端

识别符中转义字符的处理

在HTML中,标识符或类名或ID中出现的特殊字符如尖括号<>,通常需要转义成实体字符来保证语法正确,如

<div id="<span>test</span>"></div>

在JavaScript中,上例的<div>元素的id将通过.getAttribute('id')方法取值为"&#60;span>test&#62;"。在Sizzle中,它通过 getAttributeValue() 方法获取元素属性的值,并最终交给了unescapeRunes()方法解析,后文会详细分析该方法。

Sizzle引擎为了保证效率,在初始化时就会检查浏览器是否支持querySelectorAll API,以便决定使用querySelectorAll方法还是getElementsByTagName方法。如果使用querySelectorAll方法,则getAttributeValue方法内部实际上会调用querySelectorAll方法来获取属性值。因为querySelectorAll方法原生支持的字符集范围为Unicode基础平面(Basic Multilingual Plane, BMP),所以,Sizzle为了在使用 querySelectorAll方法时仍然支持非BMP字符,便在getAttributeValue()中使用了unescapeRunes方法。

unescapeRunes方法

unescapeRunes方法实际上是一个用于解析标识符转义字符的函数,它接受一个字符串作为输入,并返回一个新的字符串,其中所有转义字符都被解析为其对应的字符。

function unescapeRunes(str) {
    return str.replace(/\\([\da-f]{1,6}[\x20\t\r\n\f]?|u[\da-f]{4}[\x20\t\r\n\f]?|.)/ig, function (_, escaped) {
        var high;
        if (escaped[0] === '\\') {
            return escaped.slice(1);
        } else if (escaped[0] === 'u') {
            high = parseInt(escaped.slice(1, 5), 16);
            if (high > 0x10FFFF) {
                return escaped;
            }
            if (high > 0xD7FF && high < 0xE000) {
                return escaped;
            }
            return high < 0x10000
                ? String.fromCharCode(high)
                : String.fromCharCode(high - 0x10000 >>> 10 | 0xD800, high - 0x10000 & 0x3FF | 0xDC00);
        } else if (escaped[0] === 'x') {
            return String.fromCharCode(parseInt(escaped.slice(1), 16));
        }
        return escaped;
    });
}

该函数首先将字符串中的所有转义字符都替换为一个占位符。然后,它遍历所有占位符,并根据转义字符的类型将其解析为其对应的字符。

如果转义字符是一个反斜杠(\),则该函数会将其替换为空字符串。如果转义字符是一个u,则该函数会将其解析为一个Unicode字符。如果转义字符是一个x,则该函数会将其解析为一个ASCII字符。

最后,该函数会将所有解析后的字符连接成一个字符串并返回。

总结

unescapeRunes方法是一个非常强大的工具,它可以帮助Sizzle引擎支持更多字符集。该方法不仅可以解析标识符中的转义字符,还可以解析字符串中的转义字符。这使得Sizzle引擎能够在任何字符集中使用。