您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關JavaScript詞法都有哪些,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
輸入元素是JS詞法掃描程序拿到的最基本元素了,也就是JS程序源代碼中表達特定意義的"單詞"。
輸入元素共分為四種:
InputElement :: WhiteSpace Comment Token LineTerminator
值得注意的是,JS規范里面其實定義了兩種InputElement ,如下所示
InputElementDiv :: WhiteSpace Comment Token LineTerminator DivPunctuator
InputElementRegExp :: WhiteSpace Comment Token LineTerminator RegularExpressionLiteral
這么做是因為JS的除法運算符和正則表達式直接量都使用了/字符,在詞法分析階段,是無法區分二者的。所以JavaScript的詞法分析有兩種狀態,一種狀態是掃描InputElementDiv,另一種狀態是掃描InputElementRegExp,又所以,JS的詞法分析器應該有兩種狀態,由語法分析器來設置,JavaScript的詞法分析和語法分析必須交錯進行。
在學習web前端的過程中,難免會遇到很多的問題,這些問題可能會困擾你許久,為此我有個web開發學習交流群(
545667817 ),
里面都是 ITPUB 的小伙伴,并整理了一份最全面前端學習資料,從最基礎的HTML+CSS+JS 到移動端HTML5的項目實戰的學習資料都有整理,想學習的都可以申請加入,大家互相學習,互相交流,共同進步,每日分享不同的學習資料!
下面的一個例子說明了除法和正則表達式寫法的沖突問題:
if(a+b)/a/g;
(a+b)/a/g;
可以看到完全相同的/a/g(而且前面一段字符也相同),可能被理解為除法或者正則表達式。因為必須區分所處的語法環境,所以單單靠詞法分析無論如何也無法決定該用除法還是正則表達式來理解。
因為基本上沒有任何編輯環境會對文本做語法分析,這個問題也造成了很多語法著色系統無法很好地處理JS正則表達式。
以非語言實現者的角度,完全應該按照最上面一段產生式去理解JS的詞法。
這個詞相信不用細說,所有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,Form Feed,分頁符,字符串直接量中寫作'\f',現代已經很少有打印源程序的事情發生了,所以這個字符在JS源代碼中很少用到。
<SP>是U+0020,就是最普通的空格了。
<NBSP>是U+00A0,非斷行空格,它是SP的一個變體,在文字排版中,可以避免因為空格在此處發生斷行,其它方面和普通空格完全一樣。多數的JS編輯環境都會把它當做普通空格(因為一般源代碼編輯環境根本就不會自動折行……)
<BOM>是U+FEFF,這是ES5新加入的空白符,是Unicode中的零寬非斷行空格,在以UTF格式編碼的文件中,常常在文件首插入一個額外的U+FEFF,解析UTF文件的程序可以根據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規范承認這些字符可以被用做空白字符,但是除非對源代碼的打印、排版有特別的需求,還是應該盡量使用<SP>,尤其是考慮到,相當一批字體無法支持<USP>中的全部字符。
根據一些團隊的編碼規范,<TAB>常常用于縮進。編程語言中關于用<TAB>還是四個<SP>做縮進的爭論從未停止過,此處就不加討論了。
JS中,WhiteSpace的大部分用途是分隔token和保持代碼整齊美觀,基本上詞法分析器產生的WhiteSpace都會被語法分析器直接丟棄。
所以一些WhiteSpace能夠被去掉而完全不影響程序的執行效果。但是也有一些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風格文本編輯器中,換行是兩個字符\r\n。
<LS>是U+2028,是Unicode中的行分隔符。
<PS>是U+2029,是Unicode中的段落分隔符。
大部分LineTerminator在被詞法分析器掃描出之后,會被語法分析器丟棄,但是換行符會影響JS的兩個重要語法特性:自動插入分號和"no line terminator"規則。
考慮下面三段代碼:
var a = 1 , b = 1; a ++ b
按照JS語法的自動插入分號規則,代碼解釋可能產生歧義。
但是因為后自增運算符有no line terminator的限制,所以實際結果等價于:
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 *
這個定義略微有些復雜,實際上這就是我們所熟知的JS多行注釋語法的嚴格描述。
多行注釋中允許自由地出現MultiLineNotAsteriskChar ,也就是除了*之外的所有字符。而每一個*之后,不能出現正斜杠符/
單行注釋則比較簡單:
SingleLineComment :: // SingleLineCommentCharsoptSingleLineCommentChars :: SingleLineCommentChar SingleLineCommentCharsoptSingleLineCommentChar :: SourceCharacter but not LineTerminator
除了四種LineTerminator之外,所有字符都可以作為單行注釋。
一般情況下,不論是單行還是多行注釋都不會影響程序的意義,但是含有LineTerminator的多行注釋會影響到自動插入分號規則:
return/* */123;
return /**/ 123;
兩者會產生不同的效果。
Token是JS中所有能被引擎理解的最小語義單元。
JS中有4種Token:
Token :: IdentifierName Punctuator NumericLiteral StringLiteral
如果不考慮除法和正則的沖突問題,Token還應該包括RegularExpressionLiteral,而Punctuator中也應該添加 / 和 /=兩種符號。
IdentifierName的定義為:
IdentifierName :: IdentifierStart IdentifierName IdentifierPart IdentifierStart :: UnicodeLetter $ _ \ UnicodeEscapeSequence IdentifierPart :: IdentifierStart UnicodeCombiningMark UnicodeDigit UnicodeConnectorPunctuation <ZWNJ> <ZWJ>
IdentifierName可以以美元符$下劃線_ 或者Unicode字母開始,除了開始字符以外,IdentifierName中還可以使用Unicode中的連接標記、數字、以及連接符號。
IdentifierName的任意字符可以使用JS的Unicode轉義寫法,使用Unicode轉義寫法時,沒有任何字符限制。
IdentifierName可以是Identifier、NullLiteral、BooleanLiteral或者keyword,在ObjectLiteral中,IdentifierName還可以被直接當做屬性名稱使用。
僅當不是保留字的時候,IdentifierName會被解析為Identifier。
UnicodeLetter, UnicodeCombiningMark, UnicodeDigit, UnicodeConnectorPunctuation各自對應幾個Unicode的分類。
JS詞法名 | Unicode分類名 | code | 字符數 |
---|---|---|---|
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中的關鍵字有:
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個為了未來使用而保留的關鍵字:
FutureReservedKeyword :: one of class enum extends super const export import
在嚴格模式下,有一些額外的為未來使用而保留的關鍵字:
implements let private public interface package protected static yield
除了這些之外,NullLiteral:
NullLiteral :: null
和BooleanLiteral:
BooleanLiteral :: true false
也是保留字,不能用于Identifier。
JavaScript使用48個運算符,因為前面提到的除法和正則問題, /和/=兩個運算符被拆分為DivPunctuator。其余的運算符為:
Punctuator :: one of { } ( ) [ ] . ; , < > <= >= == != === !== + - * % ++ -- << >> >>> & | ^ ! ~ && || ? : = += -= *= %= <<= >>= >>>= &= |= ^=
所有運算符在語法分析器中作為不同的symbol出現。
JS規范中規定的數字直接量可以支持兩種寫法:十進制和十六進制整數,盡管標準中沒有提到,但是大部分JS實現還支持以0開頭的八進制整數寫法。
所以實際上JS的NumericLiteral產生式應該是這樣的:
NumericLiteral :: DecimalLiteral HexIntegerLiteral OctalIntegerLiteralnot-standard
只有十進制可以表示浮點數,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支持單引號和雙引號兩種寫法。
十進制數的小數點前和小數點后均可以省略, 所以 1. 和 .1 都是合法的數字直接量,特別地,除了0之外,十進制數不能以0開頭(這其實是為了八進制整數預留的)。
.同時還是一個Punctuator,在詞法分析階段,.123 應該優先被嘗試理解為 NumericLiteral ,而非 Punctuator NumericLiteral。
十六進制整數產生式如下:
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標記的大小寫形式,十六進制數字中的大小寫也可以任意使用。
八進制整數是非標準的,但是大多數引擎都支持:
OctalIntegerLiteral :: 0 OctalDigit OctalIntegerLiteral OctalDigit OctalDigit :: one of 0 1 2 3 4 5 6 7
JS中的StringLiteral支持單引號和雙引號兩種寫法。
StringLiteral :: " DoubleStringCharactersopt " ' SingleStringCharactersopt '
單雙引號的區別僅僅在于寫法,在雙引號字符串直接量中,雙引號必須轉義,在單引號字符串直接量中,單引號必須轉義
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
字符串中其他必須轉義的字符是\和所有換行符。
JS中支持四種轉義形式,還有一種雖然標準沒有定義,但是大部分實現都支持的八進制轉義
EscapeSequence :: CharacterEscapeSequence 0 [lookahead no DecimalDigit] HexEscapeSequence UnicodeEscapeSequence OctalEscapeSequencenot-standard
第一種是單字符轉義。 即一個反斜杠\ 后面跟一個字符這種形式。
CharacterEscapeSequence :: SingleEscapeCharacter NonEscapeCharacter SingleEscapeCharacter :: one of ' " \ b f n r t v NonEscapeCharacter :: SourceCharacter but notEscapeCharacter or LineTerminator
有特別意義的字符包括有SingleEscapeCharacter所定義的9種,見下表:
轉義字符 | 轉義結果 | 你瀏覽器中的顯示 |
---|---|---|
' | 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種字符、數字、x和u以及所有的換行符之外,其它字符經過\轉義都是自身。
十六進制轉義只支持兩位,也就是說,這種寫法只支持ASCII字符:
HexEscapeSequence :: x HexDigit HexDigit
Unicode轉義可以支持BMP中的所有字符:
UnicodeEscapeSequence :: u HexDigit HexDigit HexDigit HexDigit
LineContinuation可以被理解為一種特別的轉義。寫字符串直接量時靈活使用LineContinuation可以增加可讀性。
LineContinuation :: \ LineTerminatorSequence LineTerminatorSequence :: <LF> <CR> [lookahead no <LF> ] <LS> <PS> <CR> <CR> <LF>
為了適應Windows風格的文本,JS把"\r\n"作為一個換行符使用。
注意因為CR在某些windows風格的編輯器中沒法顯示出來,所以亂用的話會產生奇怪的效果。
正則表達式由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中也支持轉義。
RegularExpressionClassChars :: [empty] RegularExpressionClassChars RegularExpressionClassChar RegularExpressionClassChar :: RegularExpressionNonTerminator but not ] or \ RegularExpressionBackslashSequence
正則表達式中的flag在詞法階段不會限制字符,雖然只有ig幾個是有效的,但是任何IdentifierPart序列在詞法階段都會被認為是合法的。
RegularExpressionFlags :: [empty] RegularExpressionFlags IdentifierPart
一些詞法分析認為合法,但是實際上不符合正則語法的例子:
英文名 | 名稱 | 簡述 | 示例 |
---|---|---|---|
InputElement | 輸入元素 | 一切JS中合法的"詞" | |
┣Comments | 注釋 | 用于幫助閱讀的文本 | |
┃┣SingleLineComments | 單行注釋 | 以//起始的單行注釋 | //I'm comments |
┃┗MultiLineComments | 多行注釋 | 以/*起始以*/結束的注釋 | /*I'm comments,too.*/ |
┣WhiteSpace | 空白 | 起到分隔或者保持美觀作用的空白字符 | |
┣Token | 詞法標記 | 一切JS中有實際意義的詞法標記 | |
┃┣IdentifierName | 標識名稱 | 以字母或_或$開始的一個單詞,可以用于屬性名 | |
┃┃┣Identifier | 標識符 | 非保留字的IdentifierName,可以用于變量名或者屬性名 | abc |
┃┃┣Keyword | 關鍵字 | 有特殊語法意義的IdentifierName | while |
┃┃┣NullLiteral | Null直接量 | 表示一個Null類型的值 | null |
┃┃┗BooleanLiteral | 布爾直接量 | 表示一個Boolean類型的值 | true |
┃┣Punctuator | 標點符號 | 表示特殊意義的標點符號 | * |
┃┣NumericLiteral | 數字直接量 | 表示一個Number類型的值 | .12e-10 |
┃┣StringLiteral | 字符串直接量 | 表示一個String類型的值 | "Hello world!" |
┃┗RegularExpressionLiteral | 正則表達式直接量 | 表示一個RegularExpression類的對象 | /[a-z]+$$/g |
┗LineTerminator | 行終結符 | 起到分隔或者保持美觀作用的換行字符,可能會影響自動插入分號 |
簡寫 | 字符 | 概述 |
---|---|---|
<TAB> | U+0009 | tab符,用于空白 |
<VT> | U+000B | 豎向tab符,用于空白 |
<FF> | U+000C | 換頁,用于空白 |
<SP> | U+0020 | 空格,用于空白 |
<NBSP> | U+00A0 | 非斷行空格,用于空白 |
<BOM> | U+FEFF | 零寬非斷行空格,字節序標記,用于空白 |
<ZWNJ> | U+200C | 零寬非連接符,用于標識符 |
<ZWJ> | U+200D | 零寬連接符,用于標識符 |
<LF> | U+000A | 換行,用于行終結符 |
<CR> | U+000D | 回車,用于行終結符 |
<LS> | U+2028 | 行分隔符,用于行終結符 |
<PS> | U+2029 | 頁分隔符,用于行終結符 |
關于JavaScript詞法都有哪些就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。