亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JavaScript 轉義字符JSON parse錯誤研究

 更新時間:2022年10月26日 14:31:02   作者:justjavac  
這篇文章主要為大家介紹了JavaScript 轉義字符JSON parse錯誤研究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

JSON 字符串轉換為 JavaScript 對象

JSON.parse 將一個 JSON 字符串轉換為 JavaScript 對象。

JSON.parse('{"hello":"\world"}')

以上代碼輸出:

{
  hello: "world"
}

是一個 JavaScript 對象,但是仔細觀察會發(fā)現,"\world" 變成了 "world"。

那么我們繼續(xù)運行如下代碼:

JSON.parse('{"hello":"\\world"}')

出拋出異常:

VM376:1 Uncaught SyntaxError: Unexpected token w in JSON at position 11
    at JSON.parse (<anonymous>)
    at <anonymous>:1:6

Unexpected token w。

好奇心不死,繼續(xù)試,3 個反斜杠:

JSON.parse('{"hello":"\\\world"}')

結果是:

VM16590:1 Uncaught SyntaxError: Unexpected token w in JSON at position 11
    at JSON.parse (<anonymous>)
    at <anonymous>:1:6

繼續(xù),4 個反斜杠:

JSON.parse('{"hello":"\\\\world"}')

結果正常:

{
 hello: "\world"
}

  • 1個,"world"
  • 2個,Error
  • 3個,Error
  • 4個,"\world"
  • 5個,"\world"
  • 6個,Error
  • 7個,Error
  • 8個,"\\world"
  • 。。。

我們換個思路,把 JSON.parse 去掉,只輸出 JavaScript 字符串:

> 'hello'
"hello"
> '\hello'
"hello"
> '\\hello'
"\hello"
> '\\\hello'
"\hello"
> '\\\\hello'
"\\hello"

問題大概找到了。

把上面的規(guī)則帶入到之前的 JSON.parse 代碼,問題就解決了。

我們看看 JSON 的字符串解析規(guī)則:

根據這個規(guī)則,我們解析一下 "\hello",第 1 個字符是反斜杠(\),所以在引號后面走最下面的分支(紅線標注):

第 2 個字符是 h,但是反斜杠后面只有 9 條路,這個不屬于任何一條路,所以這個是個非法字符。

不只是 JSON,在很多語言中都會拋出類似 Error:(7, 27) Illegal escape: '\h' 的錯誤。

但是不知道為什么 JavaScript 偏偏可以解析這個非法轉義字符,而解決方式也很暴力:直接忽略。

在 es 規(guī)范我沒有找到具體的章節(jié)。去看看 V8 是怎么解析的吧。

引擎讀取 JavaScript 源碼后首先進行詞法分析,文件 /src/parsing/scanner.cc 的功能是讀取源碼并解析(當前最新版 6.4.286)。

找到 Scanner::Scan() 函數關鍵代碼:

case '"':
case '\'':
  token = ScanString();
break;

是一個很長的 switch 語句:如果遇到雙引號(")、單引號(')則調用 ScanString() 函數。

簡單解釋下:以上代碼是 C++ 代碼,在 C++ 中單引號是字符,雙引號是字符串。所以表示字符時,雙引號不需要轉義,但是單引號需要轉義;而表示字符串時,正好相反。此處的 C++ 轉義并不是我們今天要研究的轉義。

ScanString() 函數

在 ScanString() 函數中我們也只看重點代碼:

while (c0_ != quote && c0_ != kEndOfInput && !IsLineTerminator(c0_)) {
  uc32 c = c0_;
  Advance();
  if (c == '\\') {
    if (c0_ == kEndOfInput || !ScanEscape<false, false>()) {
      return Token::ILLEGAL;
    }
  } else {
    AddLiteralChar(c);
  }
}
if (c0_ != quote) return Token::ILLEGAL;
literal.Complete();

如果已經到了末尾,或者下 1 個字符是不能轉義的字符,則返回 Token::ILLEGAL。那么我們看看 ScanEscape 是不是返回了 false 呢?

template <bool capture_raw, bool in_template_literal>
bool Scanner::ScanEscape() {
  uc32 c = c0_;
  Advance<capture_raw>();
  // Skip escaped newlines.
  if (!in_template_literal && c0_ != kEndOfInput && IsLineTerminator(c)) {
    // Allow escaped CR+LF newlines in multiline string literals.
    if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance<capture_raw>();
    return true;
  }
  switch (c) {
    case '\'':  // fall through
    case '"' :  // fall through
    case '\\': break;
    case 'b' : c = '\b'; break;
    case 'f' : c = '\f'; break;
    case 'n' : c = '\n'; break;
    case 'r' : c = '\r'; break;
    case 't' : c = '\t'; break;
    case 'u' : {
      c = ScanUnicodeEscape<capture_raw>();
      if (c < 0) return false;
      break;
    }
    case 'v':
      c = '\v';
      break;
    case 'x': {
      c = ScanHexNumber<capture_raw>(2);
      if (c < 0) return false;
      break;
    }
    case '0':  // Fall through.
    case '1':  // fall through
    case '2':  // fall through
    case '3':  // fall through
    case '4':  // fall through
    case '5':  // fall through
    case '6':  // fall through
    case '7':
      c = ScanOctalEscape<capture_raw>(c, 2);
      break;
  }
  // Other escaped characters are interpreted as their non-escaped version.
  AddLiteralChar(c);
  return true;
}

這個函數只有 2 處返回了 false。

1、如果轉義字符后面是 u,u 后面不是 Unicode 字符時,返回 false

2、如果轉義字符后面是 x,x 后面不是十六進制數字時,返回 false

也就是說:'\u'、'\uhello'、'\u1'、'\x'、'\xx' 都拋出異常。

Uncaught SyntaxError: Invalid Unicode escape sequence

Uncaught SyntaxError: Invalid hexadecimal escape sequence

而其它非轉義字符,都直接執(zhí)行了后面的代碼:

AddLiteralChar(c);
return true;

前面的注釋也說明了這一點:

Other escaped characters are interpreted as their non-escaped version.

其他轉義字符被解釋為對應的非轉義版本。

綜上,問題的根源就是 JavaScript 和 JSON 對轉義字符的處理方式不同,導致了難以發(fā)現的 bug。JSON 遇到不能轉義的字符直接拋出異常,而 JavaScript 遇到不能轉義的字符直接解釋為對應的非轉義版本。

以上就是JavaScript 轉義字符JSON parse錯誤研究的詳細內容,更多關于JavaScript JSON parse錯誤的資料請關注腳本之家其它相關文章!

相關文章

最新評論