Sizzle引擎如何支持更多字符集?
2023-10-12 02:30:54
识别符中转义字符的处理
在HTML中,标识符或类名或ID中出现的特殊字符如尖括号<>,通常需要转义成实体字符来保证语法正确,如
<div id="<span>test</span>"></div>
在JavaScript中,上例的<div>
元素的id将通过.getAttribute('id')
方法取值为"<span>test>"
。在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引擎能够在任何字符集中使用。