源码分析:为什么 JSON.parse('2382E2') 的结果会是 238200?
发布于 3 年前 作者 18820227745 1791 次浏览 来自 分享
  • JSON.parse 的执行流程

    • 参考:Node 源码:node/deps/v8/src/json/json-parser.cc
      1. 判断数据类型
      constexpr JsonToken GetOneCharJsonToken(uint8_t c) {
        // clang-format off
        return
           c == '"' ? JsonToken::STRING :
           IsDecimalDigit(c) ?  JsonToken::NUMBER :
           c == '-' ? JsonToken::NUMBER :
           c == '[' ? JsonToken::LBRACK :
           c == '{' ? JsonToken::LBRACE :
           c == ']' ? JsonToken::RBRACK :
           c == '}' ? JsonToken::RBRACE :
           c == 't' ? JsonToken::TRUE_LITERAL :
           c == 'f' ? JsonToken::FALSE_LITERAL :
           c == 'n' ? JsonToken::NULL_LITERAL :
           c == ' ' ? JsonToken::WHITESPACE :
           c == '\t' ? JsonToken::WHITESPACE :
           c == '\r' ? JsonToken::WHITESPACE :
           c == '\n' ? JsonToken::WHITESPACE :
           c == ':' ? JsonToken::COLON :
           c == ',' ? JsonToken::COMMA :
           JsonToken::ILLEGAL;
        // clang-format on
      }
      
      
      • - 或者是 0~9 会当作 JsonToken::NUMBER
      1. 处理不同的数据类型
    switch (peek()) {
        case JsonToken::STRING:
          Consume(JsonToken::STRING);
          value = MakeString(ScanJsonString(false));
          break;
    
        case JsonToken::NUMBER:
          value = ParseJsonNumber();
          break;
    
        case JsonToken::LBRACE: {
          Consume(JsonToken::LBRACE);
          if (Check(JsonToken::RBRACE)) {
            // TODO(verwaest): Directly use the map instead.
            value = factory()->NewJSObject(object_constructor_);
            break;
          }
    
          // Start parsing an object with properties.
          cont_stack.emplace_back(std::move(cont));
          cont = JsonContinuation(isolate_, JsonContinuation::kObjectProperty,
                                  property_stack.size());
    
          // Parse the property key.
          ExpectNext(JsonToken::STRING);
          property_stack.emplace_back(ScanJsonPropertyKey(&cont));
    
          ExpectNext(JsonToken::COLON);
    
          // Continue to start producing the first property value.
          continue;
        }
    
        case JsonToken::LBRACK:
          Consume(JsonToken::LBRACK);
          if (Check(JsonToken::RBRACK)) {
            value = factory()->NewJSArray(0, PACKED_SMI_ELEMENTS);
            break;
          }
    
          // Start parsing an array with elements.
          cont_stack.emplace_back(std::move(cont));
          cont = JsonContinuation(isolate_, JsonContinuation::kArrayElement,
                                  element_stack.size());
    
          // Continue to start producing the first array element.
          continue;
    
        case JsonToken::TRUE_LITERAL:
          ScanLiteral("true");
          value = factory()->true_value();
          break;
    
        case JsonToken::FALSE_LITERAL:
          ScanLiteral("false");
          value = factory()->false_value();
          break;
    
        case JsonToken::NULL_LITERAL:
          ScanLiteral("null");
          value = factory()->null_value();
          break;
    
        case JsonToken::COLON:
        case JsonToken::COMMA:
        case JsonToken::ILLEGAL:
        case JsonToken::RBRACE:
        case JsonToken::RBRACK:
        case JsonToken::EOS:
          ReportUnexpectedCharacter(CurrentCharacter());
          // Pop the continuation stack to correctly tear down handle scopes.
          while (!cont_stack.empty()) {
            cont = std::move(cont_stack.back());
            cont_stack.pop_back();
          }
          return MaybeHandle<Object>();
    
        case JsonToken::WHITESPACE:
          UNREACHABLE();
      }
    
    • JsonToken::NUMBER 的处理函数是 ParseJsonNumber();
      • 处理字符串时对 . e 单独处理
        • 处理 e 时下一个字符如果是 - + 就忽略
      if (CurrentCharacter() == '.') {
            uc32 c = NextCharacter();
            if (!IsDecimalDigit(c)) {
              AllowHeapAllocation allow_before_exception;
              ReportUnexpectedCharacter(c);
              return handle(Smi::FromInt(0), isolate_);
            }
            AdvanceToNonDecimal();
          }
      
          if (AsciiAlphaToLower(CurrentCharacter()) == 'e') {
            uc32 c = NextCharacter();
            if (c == '-' || c == '+') c = NextCharacter();
            if (!IsDecimalDigit(c)) {
              AllowHeapAllocation allow_before_exception;
              ReportUnexpectedCharacter(c);
              return handle(Smi::FromInt(0), isolate_);
            }
            AdvanceToNonDecimal();
          }
      
      
    
    
  • 思考题:

    • 以下语句的输出结果
        1. JSON.parse(’-1111’);
        1. JSON.parse(‘11111’);
        1. JSON.parse(‘1.111’);
        1. JSON.parse(‘1111e1’);
        1. JSON.parse(‘1111e+1’);
        1. JSON.parse(‘1111e-1’);
1 回复

通常的使用场景是 JSON.parse(’“2382E2”’) ~

回到顶部