您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)JavaScript詞法都有哪些,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
輸入元素是JS詞法掃描程序拿到的最基本元素了,也就是JS程序源代碼中表達特定意義的"單詞"。
輸入元素共分為四種:
InputElement :: WhiteSpace Comment Token LineTerminator
值得注意的是,JS規(guī)范里面其實定義了兩種InputElement ,如下所示
InputElementDiv :: WhiteSpace Comment Token LineTerminator DivPunctuator
InputElementRegExp :: WhiteSpace Comment Token LineTerminator RegularExpressionLiteral
這么做是因為JS的除法運算符和正則表達式直接量都使用了/字符,在詞法分析階段,是無法區(qū)分二者的。所以JavaScript的詞法分析有兩種狀態(tài),一種狀態(tài)是掃描InputElementDiv,另一種狀態(tài)是掃描InputElementRegExp,又所以,JS的詞法分析器應(yīng)該有兩種狀態(tài),由語法分析器來設(shè)置,JavaScript的詞法分析和語法分析必須交錯進行。
在學(xué)習(xí)web前端的過程中,難免會遇到很多的問題,這些問題可能會困擾你許久,為此我有個web開發(fā)學(xué)習(xí)交流群(
545667817 ),
里面都是 ITPUB 的小伙伴,并整理了一份最全面前端學(xué)習(xí)資料,從最基礎(chǔ)的HTML+CSS+JS 到移動端HTML5的項目實戰(zhàn)的學(xué)習(xí)資料都有整理,想學(xué)習(xí)的都可以申請加入,大家互相學(xué)習(xí),互相交流,共同進步,每日分享不同的學(xué)習(xí)資料!
下面的一個例子說明了除法和正則表達式寫法的沖突問題:
if(a+b)/a/g;
(a+b)/a/g;
可以看到完全相同的/a/g(而且前面一段字符也相同),可能被理解為除法或者正則表達式。因為必須區(qū)分所處的語法環(huán)境,所以單單靠詞法分析無論如何也無法決定該用除法還是正則表達式來理解。
因為基本上沒有任何編輯環(huán)境會對文本做語法分析,這個問題也造成了很多語法著色系統(tǒng)無法很好地處理JS正則表達式。
以非語言實現(xiàn)者的角度,完全應(yīng)該按照最上面一段產(chǎn)生式去理解JS的詞法。
這個詞相信不用細(xì)說,所有JS程序員都比較熟悉。JavaScript接受5種ASCII字符為空白符,BOM以及Unicode分類中所有屬于whitespace分類的字符也可以作為空白符使用:
WhiteSpace :: <TAB> <VT> <FF> <SP> <NBSP> <BOM> <USP>
其中,<TAB>是U+0009,是縮進TAB符,也就是字符串中寫的'\t'。
<VT>是U+000B,也就是垂直方向的TAB符'\v',這個字符在鍵盤上很難打出來,所以很少用到。
<FF>是U+000C,F(xiàn)orm Feed,分頁符,字符串直接量中寫作'\f',現(xiàn)代已經(jīng)很少有打印源程序的事情發(fā)生了,所以這個字符在JS源代碼中很少用到。
<SP>是U+0020,就是最普通的空格了。
<NBSP>是U+00A0,非斷行空格,它是SP的一個變體,在文字排版中,可以避免因為空格在此處發(fā)生斷行,其它方面和普通空格完全一樣。多數(shù)的JS編輯環(huán)境都會把它當(dāng)做普通空格(因為一般源代碼編輯環(huán)境根本就不會自動折行……)
<BOM>是U+FEFF,這是ES5新加入的空白符,是Unicode中的零寬非斷行空格,在以UTF格式編碼的文件中,常常在文件首插入一個額外的U+FEFF,解析UTF文件的程序可以根據(jù)U+FEFF的表示方法猜測文件采用哪種UTF編碼方式。這個字符也叫做"bit order mark"。
<USP>表示Unicode中所有的"separator, space(Zs)"分類中的字符,包括:
字符 | 名稱 | 你瀏覽器中的顯示 |
---|---|---|
U+0020 | SPACE | |
U+00A0 | NO-BREAK SPACE | |
U+1680 | OGHAM SPACE MARK | |
U+180E | MONGOLIAN VOWEL SEPARATOR | ? |
U+2000 | EN QUAD | |
U+2001 | EM QUAD | |
U+2002 | EN SPACE | |
U+2003 | EM SPACE | |
U+2004 | THREE-PER-EM SPACE | |
U+2005 | FOUR-PER-EM SPACE | |
U+2006 | SIX-PER-EM SPACE | |
U+2007 | FIGURE SPACE | |
U+2008 | PUNCTUATION SPACE | |
U+2009 | THIN SPACE | |
U+200A | HAIR SPACE | |
U+202F | NARROW NO-BREAK SPACE | |
U+205F | MEDIUM MATHEMATICAL SPACE | |
U+3000 | IDEOGRAPHIC SPACE |
注意雖然JS規(guī)范承認(rèn)這些字符可以被用做空白字符,但是除非對源代碼的打印、排版有特別的需求,還是應(yīng)該盡量使用<SP>,尤其是考慮到,相當(dāng)一批字體無法支持<USP>中的全部字符。
根據(jù)一些團隊的編碼規(guī)范,<TAB>常常用于縮進。編程語言中關(guān)于用<TAB>還是四個<SP>做縮進的爭論從未停止過,此處就不加討論了。
JS中,WhiteSpace的大部分用途是分隔token和保持代碼整齊美觀,基本上詞法分析器產(chǎn)生的WhiteSpace都會被語法分析器直接丟棄。
所以一些WhiteSpace能夠被去掉而完全不影響程序的執(zhí)行效果。但是也有一些WhiteSpace必須存在的情況,考慮下面代碼:
1 .toString();
1.toString(); //報錯
上面一段代碼中,空白符分隔了1和.,因此它們被理解為兩個token。
1.["toString"]();
1 .["toString"](); //報錯
相反的情況。
這個也是一個非常常見的概念了,JS中只提供了4種字符作為換行符:
LineTerminator :: <LF> <CR> <LS> <PS>
其中,<LF>是U+000A,就是最正常換行符,在字符串中的'\n'。
<CR>是U+000D,這個字符真正意義上的"回車",在字符串中是'\r',在一部分Windows風(fēng)格文本編輯器中,換行是兩個字符\r\n。
<LS>是U+2028,是Unicode中的行分隔符。
<PS>是U+2029,是Unicode中的段落分隔符。
大部分LineTerminator在被詞法分析器掃描出之后,會被語法分析器丟棄,但是換行符會影響JS的兩個重要語法特性:自動插入分號和"no line terminator"規(guī)則。
考慮下面三段代碼:
var a = 1 , b = 1; a ++ b
按照J(rèn)S語法的自動插入分號規(guī)則,代碼解釋可能產(chǎn)生歧義。
但是因為后自增運算符有no line terminator的限制,所以實際結(jié)果等價于:
var a = 1 , b = 1; a; ++b;
考慮以下兩段代碼:
return 123;
return 123;
因為return有no line terminator的限制,所以第一段代碼實際等同于
return; 123;
JS的注釋分為單行注釋和多行注釋兩種:
Comment :: MultiLineComment SingleLineComment
多行注釋定義如下:
MultiLineComment :: /* MultiLineCommentCharsopt */ MultiLineCommentChars :: MultiLineNotAsteriskChar MultiLineCommentCharsopt * PostAsteriskCommentCharsopt PostAsteriskCommentChars :: MultiLineNotForwardSlashOrAsteriskChar MultiLineCommentCharsopt * PostAsteriskCommentCharsopt MultiLineNotAsteriskChar :: SourceCharacter but not asterisk * MultiLineNotForwardSlashOrAsteriskChar :: SourceCharacter but not forward-slash / orasterisk *
這個定義略微有些復(fù)雜,實際上這就是我們所熟知的JS多行注釋語法的嚴(yán)格描述。
多行注釋中允許自由地出現(xiàn)MultiLineNotAsteriskChar ,也就是除了*之外的所有字符。而每一個*之后,不能出現(xiàn)正斜杠符/
單行注釋則比較簡單:
SingleLineComment :: // SingleLineCommentCharsoptSingleLineCommentChars :: SingleLineCommentChar SingleLineCommentCharsoptSingleLineCommentChar :: SourceCharacter but not LineTerminator
除了四種LineTerminator之外,所有字符都可以作為單行注釋。
一般情況下,不論是單行還是多行注釋都不會影響程序的意義,但是含有LineTerminator的多行注釋會影響到自動插入分號規(guī)則:
return/* */123;
return /**/ 123;
兩者會產(chǎn)生不同的效果。
Token是JS中所有能被引擎理解的最小語義單元。
JS中有4種Token:
Token :: IdentifierName Punctuator NumericLiteral StringLiteral
如果不考慮除法和正則的沖突問題,Token還應(yīng)該包括RegularExpressionLiteral,而Punctuator中也應(yīng)該添加 / 和 /=兩種符號。
IdentifierName的定義為:
IdentifierName :: IdentifierStart IdentifierName IdentifierPart IdentifierStart :: UnicodeLetter $ _ \ UnicodeEscapeSequence IdentifierPart :: IdentifierStart UnicodeCombiningMark UnicodeDigit UnicodeConnectorPunctuation <ZWNJ> <ZWJ>
IdentifierName可以以美元符$下劃線_ 或者Unicode字母開始,除了開始字符以外,IdentifierName中還可以使用Unicode中的連接標(biāo)記、數(shù)字、以及連接符號。
IdentifierName的任意字符可以使用JS的Unicode轉(zhuǎn)義寫法,使用Unicode轉(zhuǎn)義寫法時,沒有任何字符限制。
IdentifierName可以是Identifier、NullLiteral、BooleanLiteral或者keyword,在ObjectLiteral中,IdentifierName還可以被直接當(dāng)做屬性名稱使用。
僅當(dāng)不是保留字的時候,IdentifierName會被解析為Identifier。
UnicodeLetter, UnicodeCombiningMark, UnicodeDigit, UnicodeConnectorPunctuation各自對應(yīng)幾個Unicode的分類。
JS詞法名 | Unicode分類名 | code | 字符數(shù) |
---|---|---|---|
UnicodeLetter | Uppercase letter | Lu | 1441 |
Lowercase letter | Ll | 1751 | |
Titlecase letter | Lt | 31 | |
Modifier letter | Lm | 237 | |
Other letter | Lo | 11788 | |
Letter number | Nl | 224 | |
UnicodeCombiningMark | Non-spacing mark | Mn | 1280 |
Combining spacing mark | Mc | 353 | |
UnicodeDigit | Decimal number | Nd | 460 |
UnicodeConnectorPunctuation | Connector punctuation | Pc | 10 |
注意<ZWNJ>和<ZWJ>是ES5新加入的兩個格式控制字符,但是目前為止實測還沒有瀏覽器支持。
JS中的關(guān)鍵字有:
Keyword :: one of break do instanceof typeof case else new var catch finally return void continue for switch while debugger function this with default if throw delete in try
還有7個為了未來使用而保留的關(guān)鍵字:
FutureReservedKeyword :: one of class enum extends super const export import
在嚴(yán)格模式下,有一些額外的為未來使用而保留的關(guān)鍵字:
implements let private public interface package protected static yield
除了這些之外,NullLiteral:
NullLiteral :: null
和BooleanLiteral:
BooleanLiteral :: true false
也是保留字,不能用于Identifier。
JavaScript使用48個運算符,因為前面提到的除法和正則問題, /和/=兩個運算符被拆分為DivPunctuator。其余的運算符為:
Punctuator :: one of { } ( ) [ ] . ; , < > <= >= == != === !== + - * % ++ -- << >> >>> & | ^ ! ~ && || ? : = += -= *= %= <<= >>= >>>= &= |= ^=
所有運算符在語法分析器中作為不同的symbol出現(xiàn)。
JS規(guī)范中規(guī)定的數(shù)字直接量可以支持兩種寫法:十進制和十六進制整數(shù),盡管標(biāo)準(zhǔn)中沒有提到,但是大部分JS實現(xiàn)還支持以0開頭的八進制整數(shù)寫法。
所以實際上JS的NumericLiteral產(chǎn)生式應(yīng)該是這樣的:
NumericLiteral :: DecimalLiteral HexIntegerLiteral OctalIntegerLiteralnot-standard
只有十進制可以表示浮點數(shù),DecimalLiteral 定義如下:
DecimalLiteral :: DecimalIntegerLiteral . DecimalDigitsopt ExponentPartopt . DecimalDigits ExponentPartopt DecimalIntegerLiteral ExponentPartoptDecimalIntegerLiteral :: 0 NonZeroDigit DecimalDigitsoptDecimalDigits :: DecimalDigit DecimalDigits DecimalDigit DecimalDigit :: one of 0 1 2 3 4 5 6 7 8 9 NonZeroDigit:: one of 1 2 3 4 5 6 7 8 9 ExponentPart:: ExponentIndicator SignedInteger ExponentIndicator :: one of e E SignedInteger :: DecimalDigits + DecimalDigits - DecimalDigits
JS中的StringLiteral支持單引號和雙引號兩種寫法。
十進制數(shù)的小數(shù)點前和小數(shù)點后均可以省略, 所以 1. 和 .1 都是合法的數(shù)字直接量,特別地,除了0之外,十進制數(shù)不能以0開頭(這其實是為了八進制整數(shù)預(yù)留的)。
.同時還是一個Punctuator,在詞法分析階段,.123 應(yīng)該優(yōu)先被嘗試?yán)斫鉃?NumericLiteral ,而非 Punctuator NumericLiteral。
十六進制整數(shù)產(chǎn)生式如下:
HexIntegerLiteral :: 0x HexDigit 0X HexDigit HexIntegerLiteral HexDigit HexDigit :: one of 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
JS中支持0x標(biāo)記的大小寫形式,十六進制數(shù)字中的大小寫也可以任意使用。
八進制整數(shù)是非標(biāo)準(zhǔn)的,但是大多數(shù)引擎都支持:
OctalIntegerLiteral :: 0 OctalDigit OctalIntegerLiteral OctalDigit OctalDigit :: one of 0 1 2 3 4 5 6 7
JS中的StringLiteral支持單引號和雙引號兩種寫法。
StringLiteral :: " DoubleStringCharactersopt " ' SingleStringCharactersopt '
單雙引號的區(qū)別僅僅在于寫法,在雙引號字符串直接量中,雙引號必須轉(zhuǎn)義,在單引號字符串直接量中,單引號必須轉(zhuǎn)義
DoubleStringCharacters :: DoubleStringCharacter DoubleStringCharactersoptSingleStringCharacters :: SingleStringCharacter SingleStringCharactersoptDoubleStringCharacter :: SourceCharacter but not double-quote " or backslash \ or LineTerminator \ EscapeSequence LineContinuation SingleStringCharacter :: SourceCharacter but not single-quote ' orbackslash \ or LineTerminator \ EscapeSequence LineContinuation
字符串中其他必須轉(zhuǎn)義的字符是\和所有換行符。
JS中支持四種轉(zhuǎn)義形式,還有一種雖然標(biāo)準(zhǔn)沒有定義,但是大部分實現(xiàn)都支持的八進制轉(zhuǎn)義
EscapeSequence :: CharacterEscapeSequence 0 [lookahead no DecimalDigit] HexEscapeSequence UnicodeEscapeSequence OctalEscapeSequencenot-standard
第一種是單字符轉(zhuǎn)義。 即一個反斜杠\ 后面跟一個字符這種形式。
CharacterEscapeSequence :: SingleEscapeCharacter NonEscapeCharacter SingleEscapeCharacter :: one of ' " \ b f n r t v NonEscapeCharacter :: SourceCharacter but notEscapeCharacter or LineTerminator
有特別意義的字符包括有SingleEscapeCharacter所定義的9種,見下表:
轉(zhuǎn)義字符 | 轉(zhuǎn)義結(jié)果 | 你瀏覽器中的顯示 |
---|---|---|
' | U+0022 | " |
" | U+0027 | ' |
\ | U+005C | \ |
b | U+0008 | |
f | U+000C | |
n | U+000A | |
r | U+000D | |
t | U+0009 | |
v | U+000B |
除了這9種字符、數(shù)字、x和u以及所有的換行符之外,其它字符經(jīng)過\轉(zhuǎn)義都是自身。
十六進制轉(zhuǎn)義只支持兩位,也就是說,這種寫法只支持ASCII字符:
HexEscapeSequence :: x HexDigit HexDigit
Unicode轉(zhuǎn)義可以支持BMP中的所有字符:
UnicodeEscapeSequence :: u HexDigit HexDigit HexDigit HexDigit
LineContinuation可以被理解為一種特別的轉(zhuǎn)義。寫字符串直接量時靈活使用LineContinuation可以增加可讀性。
LineContinuation :: \ LineTerminatorSequence LineTerminatorSequence :: <LF> <CR> [lookahead no <LF> ] <LS> <PS> <CR> <CR> <LF>
為了適應(yīng)Windows風(fēng)格的文本,JS把"\r\n"作為一個換行符使用。
注意因為CR在某些windows風(fēng)格的編輯器中沒法顯示出來,所以亂用的話會產(chǎn)生奇怪的效果。
正則表達式由Body和Flags兩部分組成:
RegularExpressionLiteral :: / RegularExpressionBody / RegularExpressionFlags
其中Body部分至少有一個字符,第一個字符不能是*(因為/*跟多行注釋有詞法沖突。)
RegularExpressionBody :: RegularExpressionFirstChar RegularExpressionChars RegularExpressionChars :: [empty] RegularExpressionChars RegularExpressionChar RegularExpressionFirstChar :: RegularExpressionNonTerminator but not * or \ or / or [ RegularExpressionBackslashSequence RegularExpressionClass RegularExpressionChar :: RegularExpressionNonTerminator but not \ or / or [ RegularExpressionBackslashSequence RegularExpressionClass
除了\ / 和 [ 三個字符之外,JS正則表達式中的字符都是普通字符。
RegularExpressionBackslashSequence :: \ RegularExpressionNonTerminator RegularExpressionNonTerminator :: SourceCharacter but not LineTerminator
用 \和一個非換行符可以組成一個RegularExpressionBackslashSequence,這種方式可以用于表示正則表達式中的有特殊意義的字符。
RegularExpressionClass :: [ RegularExpressionClassChars ]
正則表達式中,用一對方括號表示class。class中的特殊字符僅僅為]和\。
class允許為空。
class中也支持轉(zhuǎn)義。
RegularExpressionClassChars :: [empty] RegularExpressionClassChars RegularExpressionClassChar RegularExpressionClassChar :: RegularExpressionNonTerminator but not ] or \ RegularExpressionBackslashSequence
正則表達式中的flag在詞法階段不會限制字符,雖然只有ig幾個是有效的,但是任何IdentifierPart序列在詞法階段都會被認(rèn)為是合法的。
RegularExpressionFlags :: [empty] RegularExpressionFlags IdentifierPart
一些詞法分析認(rèn)為合法,但是實際上不符合正則語法的例子:
英文名 | 名稱 | 簡述 | 示例 |
---|---|---|---|
InputElement | 輸入元素 | 一切JS中合法的"詞" | |
┣Comments | 注釋 | 用于幫助閱讀的文本 | |
┃┣SingleLineComments | 單行注釋 | 以//起始的單行注釋 | //I'm comments |
┃┗MultiLineComments | 多行注釋 | 以/*起始以*/結(jié)束的注釋 | /*I'm comments,too.*/ |
┣WhiteSpace | 空白 | 起到分隔或者保持美觀作用的空白字符 | |
┣Token | 詞法標(biāo)記 | 一切JS中有實際意義的詞法標(biāo)記 | |
┃┣IdentifierName | 標(biāo)識名稱 | 以字母或_或$開始的一個單詞,可以用于屬性名 | |
┃┃┣Identifier | 標(biāo)識符 | 非保留字的IdentifierName,可以用于變量名或者屬性名 | abc |
┃┃┣Keyword | 關(guān)鍵字 | 有特殊語法意義的IdentifierName | while |
┃┃┣NullLiteral | Null直接量 | 表示一個Null類型的值 | null |
┃┃┗BooleanLiteral | 布爾直接量 | 表示一個Boolean類型的值 | true |
┃┣Punctuator | 標(biāo)點符號 | 表示特殊意義的標(biāo)點符號 | * |
┃┣NumericLiteral | 數(shù)字直接量 | 表示一個Number類型的值 | .12e-10 |
┃┣StringLiteral | 字符串直接量 | 表示一個String類型的值 | "Hello world!" |
┃┗RegularExpressionLiteral | 正則表達式直接量 | 表示一個RegularExpression類的對象 | /[a-z]+$$/g |
┗LineTerminator | 行終結(jié)符 | 起到分隔或者保持美觀作用的換行字符,可能會影響自動插入分號 |
簡寫 | 字符 | 概述 |
---|---|---|
<TAB> | U+0009 | tab符,用于空白 |
<VT> | U+000B | 豎向tab符,用于空白 |
<FF> | U+000C | 換頁,用于空白 |
<SP> | U+0020 | 空格,用于空白 |
<NBSP> | U+00A0 | 非斷行空格,用于空白 |
<BOM> | U+FEFF | 零寬非斷行空格,字節(jié)序標(biāo)記,用于空白 |
<ZWNJ> | U+200C | 零寬非連接符,用于標(biāo)識符 |
<ZWJ> | U+200D | 零寬連接符,用于標(biāo)識符 |
<LF> | U+000A | 換行,用于行終結(jié)符 |
<CR> | U+000D | 回車,用于行終結(jié)符 |
<LS> | U+2028 | 行分隔符,用于行終結(jié)符 |
<PS> | U+2029 | 頁分隔符,用于行終結(jié)符 |
關(guān)于JavaScript詞法都有哪些就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。