YvetteLau / Step-By-Step

不积跬步,无以至千里;
704 stars 66 forks source link

实现一个 JSON.parse #40

Open YvetteLau opened 5 years ago

tpxiang commented 5 years ago

JSON.parse() 方法解析一个JSON字符串,可将JSON字符串转化为对象。 JSON.parse(text [, reviver]) //第一个参数必填,一个有效的JSON字符串 第二个参数选题 是一个函数, 它用来转换已经被从text字符串转为对象的对象。对应的规则格式如下: (1)如果reviver返回的是一个有效值,则对应的属性值将替换为转换后的值。 (2)如果reviver返回的值与它接收的相同值,则不修改对应属性值。 (3)如果reviver返回的是undefined,则删除对应的属性。

a、省略第二个参数:
var jsonStr='{"name":"age","url":"www.com","sex":"男"}';
var obj=JSON.parse(jsonStr); 

b、返回修改后的值
function reviver(key,value){
  if(key=="name"){
   return "one";
}
   return value;
}
var jsonStr='{"name":"age","url":"www.com","sex":"男"}';
var obj=JSON.parse(jsonStr,reviver);

c、返回undefined,删除对应的属性
function reviver(key,value){
   if(key=="webName"){
   return "antzone";
  }else if(key=="age"){
    return undefined;
 }
    return value;
}
var jsonStr='{"name":"age","url":"www.com","sex":"男"}';
var obj=JSON.parse(jsonStr,reviver);
clark-maybe commented 5 years ago

感觉实现的不太完善,先工作,下午再完善一下

var A = "{  a: 1 , b : 'hello' }";
    var B = "{  'a': 1 , 'b' : 'hello' }";
    var C = "{'a':1,'b':'hello'}";
    var D = '{"a":1,"b":"hello"}';
    var E = '{ "a" : 1 , "b" : "hello" }';
    var E = '{ "a" : 1 , "b" : "sadfsf" }';
    var F = '{ "a" : 1 ,\n  "b" : "hello" }';
    var G = '{ "a" : 1 , "b" : window.location.href="https://www.baidu.com" }';
    //JSON.parse()  A,B,C,G都不可转,  D,E,F可以转换
    //eval() 都可以转,  G还执行了G.b的代码
    function jsonParse(str) {
        if(!str || str.constructor !== String || str.indexOf(':') === -1){
            return {};
        }else{
            let tempStr = str.replace(/'|"| |{|}/ig, '');
            let tempArr = tempStr.split(',');
            let returnObj = {};
            tempArr.map( item => {
                returnObj[item.slice(0, item.indexOf(':'))] = item.slice(item.indexOf(':') + 1, item.length);
            });
            console.log(returnObj);
        }
    }
    jsonParse(A);
sinaine commented 5 years ago
var A = "{  a: 1 , b : 'hello' }";
var B = (new Function('return'+ A))()

B 结果为 :{a: 1, b: "hello"}

KRISACHAN commented 5 years ago
eval
GCGligoudan commented 5 years ago
// 只能处理格式正确且不含空格的json
function jsonParse(json) {
  i = 0;
  str = json;
  return parseValue();
}
function parseValue() {
  if(str[i]==='n') {
    return parseNull();
  } else if(str[i]==='t') {
    return parseTrue();
  } else if(str[i]==='f') {
    return parseFalse();
  } else if(str[i]==='"') {
    return parseString();
  } else if(str[i]==='[') {
    return parseArray();
  } else if(str[i]==='{') {
    return parseObject();
  } else {
    return parseNumber();
  }
}
function parseSpace() {
  while(str[i]==' ') {
    i++;
  }
}
function parseNull() {
  let content = str.substring(i, i+4);
  // let content = str.substr(i, 4);
  if(content==='null') {
    i+=4;
    return null;
  } else {
    throw new Error('Unexpected char at pos: ' + i);
  }
}
function parseTrue() {
  let content = str.substring(i, i+4);
  // let content = str.substr(i, 4);
  if(content==='true') {
    i+=4;
    return true;
  } else {
    throw new Error('Unexpected char at pos: ' + i);
  }
}
function parseFalse() {
  let content = str.substring(i, i+5);
  // let content = str.substr(i, 5);
  if(content==='false') {
    i+=5;
    return false;
  } else {
    throw new Error('Unexpected char at pos: ' + i);
  }
}
function parseString() {
  i++;
  let result = '';
  while(str[i]!=='"') {
    result += str[i++];
  }
  i++;
  return result;
}
function parseArray() {
  i++;
  let result = [];
  while(str[i]!==']') {
    result.push(parseValue());
    if(str[i] ===',') {
      i++;
    }
  }
  i++;
  return result;
}
function parseObject() {
  i++;
  let result = {};
  while(str[i]!=='}') {
    let key = parseString();
    i++; // 略过一个冒号(:)
    let value = parseValue();
    result[key] = value;
    if(str[i]===',') i++;
  }
  i++;
  return result;
}
function parseNumber() {
  let result = '';
  while(isNumberChar(str[i])) {
    result += str[i++];
  }
  return parseFloat(result);
}
function isNumberChar(c) {
 let chars = {
   '+': true,
   '-': true,
   'e': true,
   'E': true,
   '.': true
  }
  if(chars[c]) {
    return true;
  }
  if(c>='0'&&c<='9') {
    return true;
  } else {
    return false;
  }
}

const test = '{"a":1,"b":true,"c":false,"foo":null,"bar":[1,2,3]}';
console.log(jsonParse(test));
YvetteLau commented 5 years ago

第一种方式 eval

最简单,最直观的方式就是调用 eval

var json = '{"name":"小姐姐", "age":20}';
var obj = eval("(" + json + ")");  // obj 就是 json 反序列化之后得到的对象

直接调用 eval 存在 XSS 漏洞,数据中可能不是 json 数据,而是可执行的 JavaScript 代码。因此,在调用 eval 之前,需要对数据进行校验。

var rx_one = /^[\],:{}\s]*$/;
var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
var rx_four = /(?:^|:|,)(?:\s*\[)+/g;

if (
    rx_one.test(
        json
            .replace(rx_two, "@")
            .replace(rx_three, "]")
            .replace(rx_four, "")
    )
) {
    var obj = eval("(" +json + ")");
}

JSON 是 JS 的子集,可以直接交给 eval 运行。

第二种方式 new Function

Functioneval 有相同的字符串参数特性。

var json = '{"name":"小姐姐", "age":20}';
var obj = (new Function('return ' + json))();
jodiezhang commented 5 years ago
  1. 利用function
    var jsonStr = '{"age":20,"name":"jack"}'
    var json = (new Function('return '+jsonStr))()
    console.log(typeof json)

    2.利用eval

    var rx_one = /^[\],:{}\s]*$/;
    var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
    var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
    var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
    if (
    rx_one.test(
        json
            .replace(rx_two, "@")
            .replace(rx_three, "]")
            .replace(rx_four, "")
    )
    ) {
    var obj = eval("(" +json + ")");
    }
MissNanLan commented 5 years ago
// eval  是最简单的方法,可是不太懂为什么eval中要加个“(”、“)”
var json = '{"name":"小姐姐", "age":20}';
var obj = eval("(" + json + ")"); 
chongyangwang commented 5 years ago

实现一个json.parse()

方式一 eval() 看见楼上的小姐姐提了一个eval("("+params+")"),为什么要用“()”去包裹参数,这个问题,我最初面向google搜索引擎 去研究了下 发现google不如国产百度好用,于是我面向国产百度搜索引擎去研究了下,得到的结论是,eval 接收可执行的js脚本或代码块,但不接受不可运行的js脚本作为参数"()"是让eval 把参数作为表达式去解析.

例如:

  var json = '{"name":"蔡徐坤","age":"99“}'
  console.log(eval("("+ json +")"))     //  {"name":"蔡徐坤","age":"99“}

方式二 函数

   var jsond = '{"name":"蔡徐坤","age":"99"}'
   var result = (new Function('return'+ jsond))()
   console.log(result)     //