1. 程式人生 > 其它 >json雖然簡單,但這些細節你未必知道

json雖然簡單,但這些細節你未必知道

基本介紹

JSON的全稱是JavaScript Object Notation,它並不是程式語言,而是一種可以在伺服器和客戶端之間傳輸的資料格式,本來是JavaScript的子集,但現在已獨立存在於各種程式語言中。

它有以下使用場景

  • 網路資料傳遞時,比如http請求中引數
  • 專案裡某些配置檔案,比如package.json檔案
  • 非關係型資料庫(NoSQL)將json作為儲存格式

語法

它的檔案以 .json 為字尾名,但json檔案頂層的程式碼有嚴格限制,只能寫以下三種,不然程式碼會直接標紅~

1、簡單值
數字(Number)、字串(String,不支援單引號)、布林型別(Boolean)、null型別

2、物件值
由key、value組成,key是字串型別,必須新增雙引號,值可以是簡單值、物件值、陣列值

3、陣列值
簡單值、物件值、陣列值

序列化 stringify

在http請求中攜帶引數經常用到json格式,但我們一般不會在程式碼中直接使用json,因為json資料中操作屬性並不方便,大多數時候是使用物件,將物件轉成json格式就可以通過 stringify 方法。

stringify方法有三個引數

  • 引數一(必傳),傳入一個物件,表示對於哪個物件進行stringify操作
  • 引數二(可選),傳入陣列或者函式,數組裡包括物件的key值,表示對於物件中的指定key值的資料進行序列化,傳入函式表示對指定的key/value值進行操作
  • 引數三(可選),用於改變序列化之後的json資料展現格式

我們對以下物件進行操作

const user = {
 name: "alice",
 age: 20,
 friends: ["lisa", "macus", "windy"],
 info: {
  teacher: "kiki",
 },
};
直接轉換

當只傳入一個引數時,進行基本的序列化操作

const str1 = JSON.stringify(user);
console.log(str1);
操作指定的key值
const str2 = JSON.stringify(user, ["name", "friends"]);
const str3 = JSON.stringify(user, (key, value) => {
 if (key === "age") {
  return value + 1;
 }
 return value;
});
console.log(str2);
console.log(str3);

當傳入第二個引數時,傳入陣列,表示只對 key值為“name”,“friends”的資料進行序列化;傳入函式,表示操作 key 值為“age”的時候,value+1

改變json展現格式
const str4 = JSON.stringify(user, null, 2);
const str5 = JSON.stringify(user, null, "*");
console.log(str4);
console.log(str5);

傳入第三個引數,2表示換行空2格,* 表示換行及每行內容前加 * 號

toJson方法

如果原物件中有toJSON方法,那麼stringify方法直接呼叫toJSON方法。我們給上面的物件加上toJSON方法,所有的stringify方法的執行結果都會變化。

const user = {
 name: "alice",
 age: 20,
 friends: ["lisa", "macus", "windy"],
 info: {
  teacher: "kiki",
 },
 toJSON(){
  return 'hello world'
 }
};

const str1 = JSON.stringify(user);
const str2 = JSON.stringify(user, ["name", "friends"]);
const str3 = JSON.stringify(user, (key, value) => {
 if (key === "age") {
  return value + 1;
 }
 return value;
});
const str4 = JSON.stringify(user, null, 2);
const str5 = JSON.stringify(user, null, "*");

console.log(str1);
console.log(str2);
console.log(str3);
console.log(str4);
console.log(str5);

stringify方法的執行結果都變成了 toJSON 方法的返回值

解析 parse

介面請求返回的引數中一般是json資料,我們要使用首先得通過parse方法將它轉成物件。

parse方法可以接收兩個引數

  • 引數一(必傳),json資料,表示將哪一個json資料轉成物件
  • 引數二(可選),傳入函式,表示對指定的key/value值進行操作
const str =
 '{"name":"alice","age":21,"friends":["lisa","macus","windy"],"info":{"teacher":"kiki"}}';
  
const obj1 = JSON.parse(str)
const obj2 = JSON.parse(str, (key, value)=>{
 if(key === 'age'){
  return value - 1
 }
 return value
})

console.log(obj1)
console.log(obj2)

傳入函式,處理 key值為age時的資料,此時操作 value - 1

拷貝

拷貝有以下幾種形式,拷貝出來的記憶體地址指向不一樣

直接賦值

通過等於符號可以將一個物件賦值給另一個物件。

const user = {
 name: "alice",
 info: {
  hobbies: "tennis",
 },
};
const person = user;
user.name = "lisa";

console.log("user", user);
console.log("person", person);

但它們其實指向的是同一個物件,如果操作其中一個物件的值,另外一個物件也會發生變化

在記憶體中表現如下

淺拷貝

淺拷貝只會遍歷一層,如果物件中還有value值為物件或者陣列的情況,那麼更深一層不會被拷貝,展開運算子或者Object.assign可以進行淺拷貝。

const user = {
 name: "alice",
 info: {
  hobbies: "tennis",
 },
};
const consumer = { ...user };
user.name = "lisa";
user.info.hobbies = "swimming";

console.log("user", user);
console.log("consumer", consumer);

淺拷貝後,user和consumer已經不是同一個物件了,但他們倆當中的info仍然指向同一個物件,修改其中一個info中的屬性,另一個也會變化

在記憶體中表現如下

深拷貝

深拷貝表示拷貝出來的物件與原物件完全無關,操作任意屬性都不會互相影響,通過 stringify 和 parse 方法可以實現深拷貝。

const user = {
 name: "alice",
 info: {
  hobbies: "tennis",
 },
};

const human = JSON.parse(JSON.stringify(user));
user.name = "lisa";
user.info.hobbies = "swimming";

console.log("user", user);
console.log("human", human);

此時user和human不是指向同一個物件,他們中的info物件也不是同一個物件

在記憶體中表現如下

stringify和parse實現深拷貝存在問題

雖然stringify和parse可以實現深拷貝,但是這種方式仍存在一些問題,如果物件中存在【方法、undefined、Symbol】,會直接被移除

const user = {
 name: "alice",
 height: undefined,
 [Symbol("age")]: 20,
 info: {
  hobbies: "tennis",
 },
 study() {
  console.log("I love reading~");
 },
};
const people = JSON.parse(JSON.stringify(user));

console.log("user", user);
console.log("person", people);

只剩下符合json規範的資料

因為存在這種問題,所以一般不會用stringify和parse方法,可以自己編寫處理深拷貝的方法,至於自定義深拷貝方法,留在後面的文章中詳細介紹。

以上就是json相關內容,關於js高階,還有很多需要開發者掌握的地方,可以看看我寫的其他博文,持續更新中~