Netherspite

JavaScript词法定义的源代码输入分类如下:

  • WhiteSpace,空白字符
  • LineTerminator,换行符
  • Comment,注释
  • Token,词
    • IdentifierName,标识符名称,变量名和关键字
    • Punctuator,符号,运算符和大括号等
    • NumericLiteral,数字直接量,即数字
    • StringLiteral,字符串直接量,即单双引号引起的直接量
    • Template,字符串模板,反引号`括起来的直接量
    • RegularExpressionLiteral,正则表达式直接量

需要注意的是,JavaScript对于/}有特殊的词法设计。JavaScript支持除法运算符//=,还支持正则表达式/asd/。对于},在模板字符串中是不允许}运算的,因为它是以}结尾的。

WhiteSpace

符号 含义 其他写法
<HT> 缩进符TAB 字符串中\t
<VT> 垂直方向TAB 字符串中\v
<SP> 普通空格
<NBSP> 非断行空格,在文字排版中不会导致断行 HTML中的&nbsp;

LineTerminator

  • <LF>,普通换行符,字符串中的\n
  • <CR>,“回车”,字符串中的\r,在一部分 Windows 风格文本编辑器中,换行是两个字符\r\n
  • <LS>,Unicode中的行分隔符
  • <PS>,是Unicode中的段落分隔符

Token

IdentifierName

<ZWNJ>(零宽断字符)和<ZWJ>(零宽连字符)是 ES5 新加入的两个格式控制字符,它们都是 0 宽的。

NumericLiteral

十进制的Number可以带小数,小数点的前后部分都可以省略但不能同时省略。12.toString()会报错,因为12.会被解析成数字12.0

RegularExpressionLiteral

/RegularExpressionBody/Flags,Body中至少有一个字符,且不能以*开头,除了/ \ [几个字符外都是普通字符。Flags部分可以是任意的标识符名称,但只有ig等几个有意义的标识符才是有效的。

零宽字符

零宽字符是不可见、不可打印的字符。主要用于调整字符的显示格式。

  • 零宽度空格符 (zero-width space) U+200B : 用于较长单词的换行分隔
  • 零宽度非断空格符 (zero width no-break space) U+FEFF : 用于阻止特定位置的换行分隔
  • 零宽度连字符 (zero-width joiner) U+200D : 用于阿拉伯文与印度语系等文字中,使不会发生连字的字符间产生连字效果
  • 零宽度断字符 (zero-width non-joiner) U+200C : 用于阿拉伯文,德文,印度语系等文字中,阻止会发生连字的字符间的连字效果

隐形水印

零宽字符可用于给文本打上隐形水印,增强文本的安全性。主要过程是将文本转换成二进制码,再将二进制码转换成零宽字符。用下文的函数即可将字符串转为零宽字符,再插入到文本中可实现加密。

const zeroPad = num => '00000000'.slice(String(num).length) + num;
const textToBinary = username => (
username.split('').map(char => zeroPad(char.charCodeAt(0).toString(2))).join(' ')
);
const binaryToZeroWidth = binary => (
binary.split('').map((binaryNum) => {
const num = parseInt(binaryNum, 10);
if (num === 1) {
return '&#8203;'; // zero-width space,零宽空格
} else if (num === 0) {
return '&zwnj;'; // zero-width non-joiner
}
return '&zwj;'; // zero-width joiner
}).join('') // zero-width no-break space
);

参考文章

  1. 零宽度字符
  2. JavaScript词法

 评论