美文网首页
json虽然简单,但这些细节你未必知道

json虽然简单,但这些细节你未必知道

作者: 一颗冰淇淋 | 来源:发表于2022-01-14 21:46 被阅读0次

    基本介绍

    JSON的全称是JavaScript Object Notation,它并不是编程语言,而是一种可以在服务器和客户端之间传输的数据格式,本来是JavaScript的子集,但现在已独立存在于各种编程语言中。

    它有以下使用场景

    • 网络数据传递时,比如http请求中参数
    • 项目里某些配置文件,比如package.json文件
    • 非关系型数据库(NoSQL)将json作为存储格式

    语法

    它的文件以 .json 为后缀名,但json文件顶层的代码有严格限制,只能写以下三种,不然代码会直接标红~

    1、简单值
    数字(Number)、字符串(String,不支持单引号)、布尔类型(Boolean)、null类型

    2、对象值
    由key、value组成,key是字符串类型,必须添加双引号,值可以是简单值、对象值、数组值

    3、数组值
    简单值、对象值、数组值

    1_json支持的格式.png

    序列化 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);
    
    2_stringify基本使用.png
    操作指定的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

    3_stringify的第二个参数.png
    改变json展现格式
    const str4 = JSON.stringify(user, null, 2);
    const str5 = JSON.stringify(user, null, "*");
    console.log(str4);
    console.log(str5);
    

    传入第三个参数,2表示换行空2格,* 表示换行及每行内容前加 * 号

    4_stringify的第三个参数.png
    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 方法的返回值

    5_toJSON方法.png

    解析 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

    6_parse方法.png

    拷贝

    拷贝有以下几种形式,拷贝出来的内存地址指向不一样

    直接赋值

    通过等于符号可以将一个对象赋值给另一个对象。

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

    但它们其实指向的是同一个对象,如果操作其中一个对象的值,另外一个对象也会发生变化

    7_直接赋值.png

    在内存中表现如下

    8_直接赋值内存图.png

    浅拷贝

    浅拷贝只会遍历一层,如果对象中还有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中的属性,另一个也会变化

    9_浅拷贝.png

    在内存中表现如下

    10_浅拷贝内存图.png

    深拷贝

    深拷贝表示拷贝出来的对象与原对象完全无关,操作任意属性都不会互相影响,通过 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对象也不是同一个对象

    11_深拷贝.png

    在内存中表现如下

    12_深拷贝内存图.png
    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规范的数据

    13_stringify实现深拷贝的问题.png

    因为存在这种问题,所以一般不会用stringify和parse方法,可以自己编写处理深拷贝的方法,至于自定义深拷贝方法,留在后面的文章中详细介绍。

    以上就是json相关内容,关于js高级,还有很多需要开发者掌握的地方,可以看看我写的其他博文,持续更新中~

    相关文章

      网友评论

          本文标题:json虽然简单,但这些细节你未必知道

          本文链接:https://www.haomeiwen.com/subject/lzrxhrtx.html