Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

实现一个 JSON.parse #40

Open
YvetteLau opened this issue Jul 2, 2019 · 9 comments
Open

实现一个 JSON.parse #40

YvetteLau opened this issue Jul 2, 2019 · 9 comments

Comments

@YvetteLau
Copy link
Owner

No description provided.

@tpxiang
Copy link

tpxiang commented Jul 2, 2019

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
Copy link

clark-maybe commented Jul 2, 2019

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

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
Copy link

sinaine commented Jul 2, 2019

var A = "{  a: 1 , b : 'hello' }";
var B = (new Function('return'+ A))()

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

@KRISACHAN
Copy link

eval

@GCGligoudan
Copy link

// 只能处理格式正确且不含空格的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
Copy link
Owner Author

第一种方式 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
Copy link

  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
Copy link

// eval  是最简单的方法,可是不太懂为什么eval中要加个“(”、“)”
var json = '{"name":"小姐姐", "age":20}';
var obj = eval("(" + json + ")"); 

@chongyangwang
Copy link

实现一个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)     // 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants