亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

全部開發者教程

JavaScript 入門教程

JavaScript JSON

JSON 對象包含兩個方法: 用于解析 JavaScript Object Notation (JSON) 的 parse() 方法,以及將對象/值轉換為 JSON字符串的 stringify() 方法。除了這兩個方法, JSON 這個對象本身并沒有其他作用,也不能被調用或者作為構造函數調用。

JavaScript 內置的 JSON對象 用于處理 JSON 。

JSON(JavaScript Object Notation)是一種帶有格式的文本,JavaScript 中的 JSON對象 用于處理這種文本。

JSON 對象只提供了兩個方法,一個用于序列化 JSON ,一個用于反序列化 JSON 。

這里的序列化可以理解成將JavaScirpt對象轉換成JSON,反序列化則是將JSON轉換成JavaScript對象

1. JSON.parse

JSON.parse 用于解析 JSON 格式的字符串,將 JSON 轉化成 JavaScript 對象。

JSON.parse(JSON字符串, 處理函數);

第一個參數是要轉換成對象的 JSON 字符串,第二個參數可以不傳遞/

var str = '{ "name": "baba", "age": 12, "info": { "locate": "浙江" } }';

var user = JSON.parse(str);

console.log(user); // 輸出一個 JavaScript 對象

傳遞給 JSON.parse 方法的字符串要符合 JSON 標準,否則會報錯。

第二個參數非常有趣,傳入的是一個函數,這個函數會在每個 JSON 屬性被解析的時候調用,同時會傳遞屬性名和屬性值給函數作為參數,傳入參數的返回值會作為當前遍歷到的屬性的新值。

var str = '{ "name": "baba", "age": 12, "info": { "locate": "浙江" } }';

var user = JSON.parse(str, function(key, value) {
  console.log(key, value);

  return value;
});

可以發現上述例子打印的最后一項,屬性名是可以空字符串,屬性值是解析完的結果。

修改一下例子,將返回值改成一個固定的值。

var str = '{ "name": "baba", "age": 12, "info": { "locate": "浙江" } }';

var user = JSON.parse(str, function(key, value) {
  console.log(key, value);

  return '強行修改值';
});

觀察輸出后,可以發現所有屬性都被遍歷了,并且賦值成功,但是最終 user 也變成了返回的字符串。

這是因為當解析完成后,傳入的函數會被最后調用一次,傳遞進來的值就是最終 JSON.parse 的返回值,所以對其修改后,會影響到的最終結果。

var str = '{ "name": "baba", "age": 12, "info": { "locate": "浙江" } }';

var user = JSON.parse(str, function(key, value) {
  console.log(key, value);

  if (key === '') {
    return value;
  }

  return '強行修改值';
});

對傳遞過來的屬性名為空字符串 '' 進行單獨處理即可避免這種特殊情況。

業務邏輯中很少會用第二個參數來處理解析內容。

2. JSON.stringify

JSON.stringify 用于將JavaScript對象轉換成 JSON 格式的字符串。

JSON.stringify(JavaScript對象, 處理函數, 縮進空格字符數量);

第一個參數是需要轉換成 JSON 字符串的對象。

第二個參數可以是個函數,也可以是個數組。
如果是函數,則每一個屬性在處理的時候就被調用這個函數,同時屬性名和屬性值作為參數傳遞給這個函數,并且函數的返回值作為這個處理屬性的值。
如果是數組,則只有屬性名在數組中的屬性才會被處理,不傳遞則默認處理整個對象。
如果第二個參數傳遞 null ,也就是不做特殊處理,在使用到第三個參數的時候,第二個參數會傳遞 null 。

第三個參數可以傳遞數字,也可以傳遞字符串,傳遞了這個參數會對結果做格式化,具有一定的格式,參數的值決定格式化的樣式。
如果是數字,則使用對應長度的空格來縮進,長度 1 到 10 ,比 1 小則表示不縮進。
如果是字符串,則會使用傳入的字符串進行縮進,傳入的字符串長度超過 10 ,則會截取前 10 個作為縮進字符。

var user = {
  name: '小明',
  age: 14,
  skill: ['HTML', 'Java'],
};

var json = JSON.stringify(user);

console.log(json);
// 輸出:{"name":"小明","age":14,"skill":["HTML","Java"]}

第二個參數用起來和 parse 方法的第二個參數類似。

var user = {
  name: '小明',
  age: 14,
  skill: ['HTML', 'Java'],
};

var json = JSON.stringify(user, function(key, value) {
  console.log(key, vlue);

  return value;
});

console.log(json);

根據上述例子可以看到,先輸出的屬性為空字符串,屬性值為被處理對象,所以如果不想操作原對象,需要做特殊處理。

var user = {
  name: '小明',
  age: 14,
  skill: ['HTML', 'Java'],
};

var json = JSON.stringify(user, function(key, value) {
  if (key === '') {
    return value;
  }

  return '我是處理過的值';
});

console.log(json);

這樣處理后,最終處理完的 JSON 字符串的屬性值都是函數的返回值了。

第三個參數會在做一些工具類調試的時候常用到。

var obj = [
  {
    path: '/',
    component: 'function() {}',
    children: [
      {
        path: 'note',
        component: 'function() {}',
      },
      {
        path: 'friends',
        component: 'function() {}',
      }
    ]
  },
  {
    path: '*',
    component: 'function() {}',
  }
];

var json1 = JSON.stringify(obj, null);
var json2 = JSON.stringify(obj, null, 2);
var json3 = JSON.stringify(obj, null, '*-*');

console.log(json1); // 沒有格式
console.log(json2); // 使用兩個空格控制的縮進
console.log(json3); // 使用 *-* 控制的縮進

傳入參數后就會將處理后的 JSON 字符串進行格式化,縮進部分根據傳入的參數值決定。

圖片描述

3. 其他注意點

3.1 深拷貝

可以配合 JSON 的兩個方法,對對象進行深拷貝。

var obj = {prop: 'value'};

var newObj = JSON.parse(JSON.stringify(obj));

newObj.prop = 'new value';

console.log(obj);
console.log(newObj);

根據結果可以看到新的對象修改,沒有影響到原對象,兩者之間不存在引用關系。

3.2 序列化規則

使用 JSON.stringify 有些內置規則。

  • 如果對象中存在包裝對象,則在轉換過程中會變成原始值。
var obj = {
  string: new String('A promise is a promise.'),
  number: new Number(996),
};

var result = JSON.stringify(obj);

console.log(result); // 輸出:"{"string":"A promise is a promise.","number":996}"
  • 如果轉換的對象或者對象下的屬性存在 toJSON 方法,那么這個方法的返回值會作為轉換結果。
var user = {
  nickname: 'joker',

  toJSON: function() {
    return 'hahahahahahaha';
  },
}

var result = JSON.stringify(user);

console.log(result); // 輸出:"hahahahahahaha"

可以看到結果為 toJSON 方法的返回值。

  • 除了數組以外的對象,轉換結果順序為隨機。
var obj = {
  b: 2,
  c: 3,
  a: 1,
};

如以上對象,轉換的結果有可能是以下情況中的一種:

"{"a":1,"b":2,"c":3}"
"{"a":1,"c":3,"b":2}"
"{"b":2,"a":1,"c":3}"
"{"b":2,"c":3,"a":1}"
"{"c":3,"b":2,"a":1}"
"{"c":3,"a":1,"b":2}"
  • undefined、ES6 中的 symbol 值、函數在轉換過程中都會被忽略,當然函數如果具有 toJSON 方法依然會優先選擇 toJSON 方法的結果。
var fn = function() {};
fn.toJSON = function() {return '我是函數'};

var result = JSON.stringify({
	a: fn,
	b: Symbol(1),
	c: undefined,
  d: function() {},
});

console.log(result);
  • 存在循環引用,則會報錯
var obj1 = {
  prop1: 1,
};
var obj2 = {
  prop1: 1,
};

obj1.prop2 = obj2;
obj2.prop2 = obj1;

JSON.stringify(obj1); // TypeError: Converting circular structure to JSON

兩個對象相互引用之后,進行系列化就會拋出錯誤。

  • 在 ES6 中,symbol 可以作為對象的屬性值,但在處理的時候都會被忽略。
var symbol = Symbol();

var obj = {
  prop1: 'value1',
  [symbol]: 'value2',
};

console.log(obj);

var result = JSON.stringify(obj);

console.log(result); // 輸出:{"prop1":"value1"}
  • null、正負 Infinity、NaN 在序列化時都會被當作 null 。
var obj = {
  null: null,
  infinity1: +Infinity,
  infinity2: -Infinity,
  NaN: NaN,
};

var result = JSON.stringify(obj);

console.log(result); // 輸出:{"null":null,"infinity1":null,"infinity2":null,"NaN":null}

4. 小結

JSON 幾乎是目前前后端交互最常用的數據格式,所以 JSON 對象使用的頻率也很高。

在使用 JSON.parse 反序列化的時候,如果 JSON 格式不符合規范,是會報錯的,日常開發中建議封裝一層 JSON 的方法,將錯誤集中處理,方便定位與上報錯誤。