0%

JavaScript琐碎基础---学习手记

JavaScript语语法基础部分一览,包括面试常见的“深浅拷贝”、数据结构操作(如数组插入等)需熟记于心。

? 条件运算符

1
let result = condition ? value1 : value2;

注:如果条件为真,则返回value1;否则,返回value2

‘??’空值合并

1
let res = a ?? b;
  1. 如果a已定义,则结果为a
  2. 否则,结果为b

用例

1
2
let user = "John";
alert(user ?? "Anonymous");

对象克隆

Object.assign(浅拷贝)

1
Object.assign(target_object, [source_object1, source_object2, source_object3...])

用例

1
2
3
4
5
6
7
8
let user = { name:"Will"}

let info = {age: 18, grade: "Master"};
let drive = {canDrive: true};

Object.assign(user, info, drive); // user = {name:"Will", age: 18, grade: "Master", canDrive: true}

let new_user = Object.assign({}, user, info, drive); // 返回一个新的对象

使用for loop实现

1
2
3
4
5
6
7
8
9
10
let user = {
name : "Will",
age : 18,
grade: "Master"
};

let clone = {};
for (let key in user) {
clone[key] = user[key];
}

深层克隆(深拷贝)

由于上述的对象克隆(无论是for loop还是Object.assign)都是假设所有的属性为原始类型,但是对于对象的引用类型,则会失效。因为它会直接复制其引用,因此双方仍然会共用一个属性值

因此,我们需要深层克隆。

Json.parse(JSON.stringify(xxxx)) — 通常

  • Pros:简单易用
  • Cons:
    1. 会忽略undefined
     2. 会忽略symbol
     3. 不能序列化函数
     4. 不能解决循环引用的问题
    
1
2
3
4
5
6
7
8
9
10
11
12
let a = {
age : 10,
jobs: {
first: "police",
second: "pilot"
}
}

let b = JSON.parse(JSON.stringify(a));

a.jobs.first = "programmer";
console.log(b.jobs.first); // police

MessageChannel(消息通道)

  • Pros:

    1. 能解决undefined
     2. 能解决循环引用
    
  • Cons:异步函数

1
2
3
4
5
6
7
function deepClone(obj) {
return new Promise(resolve => {
const {port1, port2} = new MessageChannel();
port2.onmessage = (ev)=>{resolve(ev.data);}
port1.postMessage(obj);
});
} //之后再看

垃圾回收

简言之:JS引擎有一个被称作垃圾回收器的东西在后台自动运行,它监控所有对象的状态,然后删除那些已经不可达的对象(即不能访问到它了)

构造器

构造函数

约定:

  1. 命名以大写字母开头
  2. 只能由new操作符来执行

可选链 ?.

简言之:如果可选链前面的部分是null或undefined则返回undefined;否则,返回该部分以及后面的访问属性

value?.prop:

注:这里的不存在指的是该变量为null和undefined

  • 如果value存在,则返回value.prop
  • 如果value不存在(即为null或undefined),则返回undefined,而不会像直接用value.prop一样报错

例子:

1
2
3
4
5
6
let user = {};
user?.address?.name; // undefined

let admin = {name: "Will"};
admin?.name; // "Will"
admin?.age; // undefined

扩展

obj?.prop

obj?.[prop]

obj.methodName?.()

最后

注意使用?.时,一定要确保其前面的变量已经声明,否则同样会报错

Symbol类型

定义

“Symbol”表示唯一的标识符,使用Symbol()来创建这种类型的值

1
2
3
let uniqueId = Symbol();

let uniqueId2 = Symbol("id"); // "id"为Symbol的一个描述

Symbol保证唯一性,即使具有相同描述的Symbol,它们的值也不同

Symbol不会被自动转化为字符串

1
2
3
let uniqueId = Symbol('id');

uniqueId.toString(); // Symbol(uniqueId)

Symbol可以用来创建对象的“隐藏”属性

可以作为对象的属性键

注:在对象字面量{…}中使用Symbol作为属性键时,需要将它用方括号括起来

1
2
3
4
5
6
let id = Symbol('id');

let user = {
name: "will",
[id]: 1;
};

Symbol在for…in循环中会跳出,但Object.assign方法却不会忽略symbol属性键

全局Symbol注册表

注:使用Symbol.for("key")的方式从全局注册表中读取描述为key的Symbol,如果不存在则创建一个新的Symbol(Symbol(key)),并通过给定的key将其存储在注册表中。

1
let id = Symbol.for('id');

反向调用

1
2
let sym = Symbol('id');
Symbol.keyFor(sym); // id

数据类型

数字类型

toString(base)

  • base表示进制,例如base=2,就以二进制的形式进行返回该数的字符串形式

  • base的范围是2-36,常用的是2、16、36

  • 如果在数字上直接调用该方法,则要使用2个点。如;100..toString(2),第一个点JS识别为小数点

1
2
3
4
let num = 2;

num.toString(2); // '10'
num.toString(10); // '2'

舍入rounding

  • Math.floor 向下取整
  • Math.ceil 向上取整
  • Math.round 四舍五入
  • Math.trunc 舍去小数点后
  • toFixed(n) 四舍五入保留小数点后n位,返回一个字符串
1
2
let num = 12.36;
num.toFixed(1); // 12.4

不精确计算

0.1 + 0.2 !== 0.3

原因:0.1 + 0.2的结果为0.3000…04。这是因为数字以其二进制的形式存储在内存中,即一个1和0的序列,同时在二进制中,可以保证以2为整数次幂能精确存储,因此0.1和0.2在二进制中均为无限二进制,无法被精确存储。

解决方法:使用toFixed()舍去小数

1
2
3
let sum = 0.1 + 0.2;
sum.toFixed(2); // '0.30'
+sum.toFixed(2); // 0.3

isFinite和isNaN

  • Infinity & -Infinity 表示无穷大
  • NaN表示Not-A-Number

isNaN判断一个参数是否为Number(判断之前先将它们专为数字然后再判断)

1
2
3
isNaN("str"); // true
isNaN("12"); // false
isNaN(12); // false

parseInt & parseFloat

+Number()可以进行数字转换,但如果其不是数字字符串则会转换失败并返回NaN

使用parseInt和parseFloat可以解决这个问题

1
2
3
4
parseInt('100px'); // 100
parseFloat('12.555px'); // 12.555
parseInt('px1000'); //NaN
parseFloat('px12.555'); //NaN

parseInt(str, base)

1
parseInt('0xff', 16); // 255

内建Math其他函数

  • Math.random() — 返回一个0-1的随机数(不包括1)
  • Math.max(a, b, c, …) —- 返回一个最大数
  • Math.min(a, b, c, …) —- 返回一个最小数
  • Math.pow(n, power) — 返回npower

e

en(n为数字)表示 $*10^{n}$

1
let Twothousand = 2e3; // 2000

字符串

引号

1
2
3
let s1 = 's';
let s2 = "s";
let s3 = `s`;

反引号允许

  1. 使用${...}将任何表达式嵌入
  2. 换行
1
let s4 = `s2是${s3}。1+2=${sum(1,2)}`;

内置函数

length属性

1
2
let word = "William";
word.length; // 7

获取某一位置的字符

1
2
3
let word1 = "Hello";
word[0]; // H
word.charAt(0); // H

可以使用for ... of遍历字符串

1
2
3
for (let alphabet of 'Hello') {
alert(alphabet); // H e l l o
}

字符串unmutable

大小写

$\textcolor{blue}{toUpperCase(), toLowerCase()}$

1
2
'hello world'.toUpperCase(); // HELLO WORLD
'Hello World'.toLowerCase(); // hello world

查询子字符串

string.indexOf(substr, pos),substr为要查询的子字符串,pos为从指定位置开始查询

1
2
let word = 'Hello Word!';
word.indexOf('World'); // 6

Others:

1
2
3
"Hello".includes("el"); // true
"Hello".startWith('He'); // true
"Hello".endWith('lo'); //true

获取子字符串☑️

slice( start[, end) )

1
2
let word = "HelloWorld";
word.slice(0,3); // Hel

substr( start[, length )

1
2
let word = "HelloWorld";
word.substr(1,3); // ell

比较字符串

小写字母总是大于大写字母

1
'a' > 'Z'; // true

在JS内部,所有字符串都使用UTF-16编码(即:每个字符都有相应的数字代码)

1
2
3
"zealand".codePointAt(0); // 122
"Zealand".codePointAt(0); // 90
String.fromCodePoint(90); // Z

数组Array

1. 声明

1
2
3
4
5
6
7
8
9
10
11
12
13
let arr = new Array();
let arr2 = [];

let fruits = ["Apple", "Orange", "Plum"];

fruits[0]; // "Apple"

fruits[1] = "Pear";

fruits.length; // 3

let arr3 = ['Apple', {name:'Will'}, true, function() {alert('Hello');}]; // 任意类型数据

2. 队列Queue和栈Stack

  1. 队列Queue — First In First Out

    push —— 在末端加一个元素

    shift —— 取出队首一个元素,并返回该值

    1
    2
    3
    4
    5
    6
    7
    let fruits = ["Apple", "Orange", "Pear"];

    fruits.push("Banana"); //
    fruits; // "Apple", "Orange", "Banana"

    fruits.shift(); // "Apple"
    fruits; // "Orange", "Banana"
  2. 栈Stack — Last In First Out

    push

    pop —— 从末端取出一个元素,并返回该值

    1
    2
    fruits.pop(); // "Pear"
    fruits; // "Apple", "Orange"
  3. unshift()

    在数组首端添加元素

    1
    2
    fruits.unshift("Banana");
    fruits; // "Banana", "Apple", "Orange"

    3.内部

数组本质上也是一个对象,arr[0]本质上类似obj[key],arr是对象,数字是键

4.性能

push/pop运行较快,而shift/unshift运行较慢

5.循环

1
2
3
4
5
6
7
8
9
10
11
let arr = ["Apple", "orange", "Mango"];

// for loop
for (let i = 0; i<arr.length; i++) {
alert(arr[i]);
}

// for...of loop
for (let element of arr) {
alert(element);
}

6. length 可修改

7. toString()

1
2
3
4
let arr = ["Apple", "orange", "Mango"];

String(arr); // 'Apple,orange,Mango'
arr.toString(); // 'Apple,orange,Mango'

数组的方法‼️

splice( start[, deleteCount, element1, element2, … ) — in-place

可以实现插入、删除

1
2
3
let arr = ["I", "study", "JavaScript", "right", "now"];
arr.splice(0, 3, "Let's", "dance"); // ["I", "study", "JavaScript"];
arr; // ["Let's", "dance", "right", "now"]

slice( start[, end) )

1
2
let arr = ['h', 'e', 'l', 'l', 'o'];
let newArr = arr.slice(1,3) // newArr = ['e', 'l']

concat(arg1, arg2, …)

1
2
3
4
let arr = [1,2,3];
arr.concat(5, [7,9]); // [1,2,3,5,7,9]
let obj1 = {id: 1, name: "Will"};
arr.concat(obj1); // [1,2,3,{id: 1, name: "Will"}]

遍历:forEach

array.forEach可以实现为数组中的每个元素都运行一个函数

1
2
3
4
let arr = [...];
arr.forEach(function(item, index, array) {
...
});

用例如下:

1
2
3
4
let arr = ["Nottingham", "London", "Manchestor"];
arr.forEach(function(item, index, array) {
console.log(`${item} is at index ${index} in ${array}`);
});

搜索

indexOf, lastIndexOf, includes

1
2
3
4
5
6
7
8
let arr = [1,2,3];

// arr.indexOf(item, from); 从索引from开始找item,找到返回index,否则返回-1
// arr.lastindexOf(item, from); 同上,但从右向左
// arr.includes(item, from); 从索引from开始搜索item,找到返回true,否则返回false

arr.indexOf(2, 1); // 1
arr.includes(3); // true

find, findindex

1
2
3
4
5
let arr = [1,2,3];
let result = arr.find(function(item, index, array) {
// 返回true,则搜索停止并返回item
// 返回false则返回undefined
});

用例

1
2
3
4
5
6
7
8
let users = [
{id:1,name:"Will"},
{id:2,name:"Dion"},
{id:3,name:"Akshay"}
];

let user = users.find((user)=>{return user.id==1});
user.name; // "Will"

filter⭐️

与find的类似,不过区别在于如果其返回true,搜索会继续直到遍历完整个数组,并返回所有匹配元素组成的数组。

1
2
let user = users.filter(user => item.id <= 2);
user.length; // 2

转换数组

map

对数组中的每个元素调用map参数中的该函数,并返回结果数组

1
2
3
let res = arr.map(function(item, index, array) {
// 返回新值而不是当前元素
})

用例

1
2
3
let names = ["Will", "Dions", "Akshay"];
let lengths = names.map(name => name.length);
lengths; // [4,5,6]

sort — in-place

对数组进行原位(in-place)排序,更改数组中元素的顺序,其语法为数组.sort(排序函数)

1
2
3
4
5
6
7
8
9
10
let arr = [1,2,9,4];

function compare(a,b) {
if (a>b) return 1;
if (a==b) return 0;
if (a<b) return -1;
}

arr.sort(compare); // [1,2,4,9]
arr; // [1,2,4,9]

实际上,排序函数可以返回任意数字(正数代表”大于”,负数代表”小于”);同时使用箭头函数会更简洁

1
2
3
let arr = [2,9,8,1];
arr.sort( (a,b) => a-b ); //[1,2,8,9]
arr; // [1,2,8,9]

localeCompare

1
2
3
let countries = ['Österreich', 'Andorra', 'Vietnam'];

countries.sort( (a,b) => a.localeCompare(b) ); // [Andorra,Österreich,Vietnam]

reverse — in-place

1
2
3
4
5
let arr = [1,2,3];

arr.reverse();

arr; // [3,2,1]

split, join

  1. 分割字符串为数组

    1
    2
    3
    let names = "Will, Dion, Akshay";
    let arr = names.split(', ');
    arr; // ["Will", "Dion", "Akshay"]
  2. 合并数组元素为字符串

    1
    2
    let strName = arr.join(" ");
    strName; // "Will Dion Akshay"

reduce, reduceRight

用于根据数组计算单个值

1
2
3
let value = arr.reduce(function(accumulator, item, index, array) {
// ...
}, [initial]);
  • accumulator本质上是个累加器。

  • 应用reduce函数时,它会将上一个参数函数调用的结果作为第一个参数传递给下一个函数

1
2
3
let arr = [1,2,3,4,5];
let res = arr.reduce( (sum, current) => sum+current, 0 );
res; // 15

Array.isArray

数组是基于对象的,因此无法使用typeof进行判断

1
2
3
4
typeof []; // object

Array.isArray( [] ); // true
Array.isArray( {} ); // false

可迭代对象(Iterable Object)

可迭代对象是数组的泛化,任何对象都可以被定制为可在for...of循环中使用的对象。

Symbol.iterator

为对象添加一个名为Symbol.iterator方法,便可使其可迭代

  1. for...of循环时,会调用该方法,同时该方法须返回一个迭代器(即有next()方法的对象)
  2. 此后,for...of仅作用于这个被返回的迭代器
  3. for...of会调用next()方法来取得下一个数值
  4. next()返回的结果对象格式必须为:{done: Boolean, value: any}。其中当done=true时,迭代结束,否则value为下一个值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
let range = {
from: 1,
to: 5
};

// 添加一个名为Symbol.iterator方法
range[Symbol.iterator] = function() {

// 返回一个迭代器
return {
current: this.from,
last: this.to,

// 加入next()方法
next() {
// 返回要求格式的对象
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done:true };
}
}
};
};

for (let num of range) {
num; // 1,2,3,4,5
}

字符串是可迭代的

1
2
3
for (let char of 'test') {
char; // 't', 'e', 's', 't'
}

显示调用迭代器

1
2
3
4
5
6
7
8
9
let str = 'test';

let iterator = str[Symbol.iterator]()

while (true) {
let res = iterator.next();
if (res.done) break;
res.value;
}

Array.from — 将可迭代或类数组转化为数组对象(可使用数组的方法)

概念

  • Iterable(可迭代): 实现了Symbol.iterator方法的对象
  • Array-like(类数组): 有索引和length属性的对象

用例

1
2
3
4
5
6
7
8
9
let arrayLike = {
0: "Hello",
1: "World",
length: 2
};

let arr = Array.from(arrayLike);
arr.pop(); // "World"
arr; // ["Hello"]

Array.from还提供了一个可选参数—映射(mapping)函数

1
Array.from(obj, mapFunction, thisArg); // thisArg允许我们为设置该函数设置this

用例

1
2
let arr = Array.from(range, num => num * num); // 该函数会被应用于数组中的每个元素
arr; // [1,4,9,16,25]

字符串转换为数组

1
2
3
4
5
let str = 'test';

let strArray = Array.from(str);

strArray; // ['t','e','s','t']

Map and Set — 映射和集合

Map

  • Map是带键的数据项,但与对象(会将其转换为字符串)不同,键可以是任意类型
  • 使用set、get方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
let map = new Map();
let will = {name:"Will"};

map.set('1', 'hello'); // 字符串键
map.set(1, 'world'); // 数字键
map.set(true, '!!!'); // 布尔值键
map.set(will, 111); // 对象键

map.get('1'); // 'hello'
map.get(1); // 'world'
map.get(true); // '!!!'
map.get(will); // 111

map.size; // 3

链式调用

map.set调用会返回map本身

1
2
3
map.set('1', 'hello')
.set(1, 'world')
.set(true, '!!!');

Map迭代

在map中使用循环,可使用如下方法:

  • map.keys() — 返回所有的键
  • map.values() — 返回所有的值
  • Map.entries() — 返回所有的键值对
1
2
3
4
5
6
7
8
9
10
11
12
13
let recipe = new Map([
['tomatoes', 500],
['onion', 300],
['bell pepper', 50]
]);

for (let veg of recipe.keys()) {
veg; // tomatoes, onion, bell pepper
}

for (let entry of recipe.entries()) {
console.log(entry); // ['tomatoes', 500], ...
}

forEach

1
2
3
recipe.forEach( (value, key, map) => {
console.log(`${key}: ${value}`);
} )

Object.entries — 从对象—>Map

new Map([key, value], [key, value], ...)

Object.entries()可以返回对象的键值对数组(其格式完全符合Map所需)

1
2
3
4
5
6
7
8
let obj = {
name: "Will",
age: 30
};

let map = new Map(Object.entries(obj)); // Object.entries返回键值对数组[['name','Will'], ['age', 30]]

console.log(map.get('name'));

Object.fromEntries — 从Map—>对象

给定一键值对数组返回一个对象

1
2
3
4
5
6
7
let prices = Object.fromEntries([
['banana', 1],
['orange', 2],
['apple', 3]
]);

console.log(prices); // { banana: 1, orange: 2, apple: 3 }

Set

Set是集合并且无重复值,其方法有:

  1. new Set(iterable) — 创建一个set,如有iterable,将从其中复制值到set中
  2. set.add(value) — 添加一个值并返回set
  3. set.delete(value) — 删除值,如该值存在则返回true,否则返回false
  4. set.has(value) — 如value存在set中,则返回true;否则返回false
  5. set.clear() — 清空set
  6. set.size — 返回元素个数

可迭代(iterable)

可以使用for...offorEach

1
2
3
4
5
let set = new Set(["oranges", "apples", "bananas"]);

for (let value of set) console.log(value);

set.forEach((value, valueAgain, set) => console.log(value));

用于迭代的方法(同Map)

  • set.keys()
  • set.values()
  • set.entries()

弱映射和弱集合(WeakMap & WeakSet)

Object.keys, values, entries

  • Object.keys(obj) — 返回一个包含该对象的所有键的数组
  • Object.values(obj) — 返回一个包含该对象的所有值的数组
  • Object.entries(obj) — 返回一个包含该对象所有键值对(即[key, value])的数组

解构赋值

数组(Array)解构

基本结构为:[变量名1, 变量名2, ...]=[...]

  1. 变量名无所谓

    1
    2
    3
    let arr = ["Will", "Koo"];

    let [firstName, lastName] = arr;
  2. 使用逗号忽略不想要的元素

    1
    2
    3
    4
    let [firstName, , thirdOne] = ["Will", "Sam", "Dion", "Ricky"];

    firstName; // "Will"
    thirdOne; // "Dion"
  3. 任何可迭代对象都可以用数组解构赋值

    1
    2
    3
    let [a,b,c] = "USA";
    [a,b,c]; //['U','S','A']
    let [one, two, three] = new Set(['U','S','A']);
  4. 交换变量值

    1
    2
    3
    4
    5
    6
    let guest = "People";
    let admin = "Will";

    [guest, admin] = [admin, guest];

    [guest, admin]; // ['Will', "People"]
  5. 剩余…

    1
    2
    3
    let [name1, name2, ...rest] = ["Will", "Dion", "Akshay", "Ricky", "Sam"];

    rest; // ["Akshay", "Ricky", "Sam"]
  6. 默认值

    1
    2
    3
    4
    let [name1="Anonymous", name2="Will"] = ["Dion"];

    name1; // "Dion"
    name2; // "Will"

对象解构

基本语法:let {var1, var2, ...} = {var1:..., var2:..., ...},其中等号左侧的变量名顺序不重要,但变量名必须与右侧对象中的属性名一致

用例:

1
2
3
4
5
6
7
let personAdmin = {
name: "Will",
age: 24,
major: "CS"
};

let {name, age, major} = personAdmin;
  1. 更改左侧的变量名

    1
    2
    3
    4
    let {name: n, age: a, major} = personAdmin;
    n; // "Will"
    a; // 24
    major; // "CS"
  2. 默认值 =

    1
    2
    3
    4
    5
    6
    7
    8
    let person = {
    name: "Dave"
    };

    let {name, age=90, job="Invester"} = person;
    name; // "Dave"
    age; //90
    job; // "Inverster"

    结合:

    1
    2
    3
    4
    let {name, age: a = 90, job: j = "Invester"} = person;
    name; // "Dave"
    a; //90
    j; // "Inverster"
  3. 剩余…

    1
    2
    3
    4
    let {name, ...others} = personAdmin;

    name; // "Will"
    others; // {age: 24, major: "CS"}
  4. 提前声明变量,之后调用

    不使用let时进行解构赋值,需要在最外侧加一个圆括号。这是因为JS会将主代码流的{...}当作一个代码块

    1
    2
    3
    let name, age, major;

    ({name, age, major} = personAdmin);

JSON

定义:JSON(JavaScript Object Notation)是表示值和对象的通用格式

JSON.stringify — 将对象转为JSON

1
2
3
4
5
6
7
8
let student = {
name: 'John',
age: 30,
isAdmin: false
};

let json = JSON.stringify(student);
typeof json; // 'string'
  • 注:通过JSON.stringify()方法将对象转换为字符串的过程称为 JSON编码序列化(serialized)字符串化编组化

  • JSON支持一下数据类型:

    1. Object {...}
    2. Array [...]
    3. Primitive:
      1. string
      2. number
      3. boolean
      4. null
  • 不能有循环引用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    let a = {
    rank: 1
    };

    let b = {
    rank: 2
    };

    b.teacher = a;
    a.student = b;

    JSON.stringfiy(b); // Error

JSON.stringify完整语法

JSON的完整语法为: JSON.stringify(value, replacer, space)

其中:

  1. value — 要编码的对象
  2. replacer — 要编码的属性数组(或者使用映射函数)
  3. space — 用于格式化的空格数量
  • 使用完整语法避免循环引用报错

    1. 使用属性数组
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    let a = {
    rank: 1
    };

    let b = {
    rank: 2
    };

    b.teacher = a;
    a.student = b;

    JSON.stringify(b, ['rank', 'teacher']); // '{"rank":2,"teacher":{"rank":1}}'
    1. 使用映射函数
    1
    2
    3
    JSON.stringify(b, function replacer(key, value) {
    return (key === 'student') ? undefined : value;
    });

自定义toJSON

说明:如果对象有toJSON方法,则JSON.stringify会自动调用该方法

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let a = {
rank: 1,
toJSON() {
return this.rank;
}
};

let b = {
rank: 2
};

b.teacher = a;

JSON.stringify(a); // '1'
JSON.stringify(b); // '{"rank":2,"teacher":1}'

JSON.parse — 将JSON字符串转换为合适的数据格式

基本语法:JSON.parse(str, reviver)

其中:

  • str:要解析的JSON字符串
  • reviver:可选函数,该函数对每个键值对(key, value)调用,并可改变其值
1
2
3
let nums = "[0,1,2,3]";
let arrNums = JSON.parse(nums);
arrNums; // [0,1,2,3]

使用reviver

用例:

1
2
3
4
5
6
7
8
9
10
11
let meetingJSON = '{"title": "Conference", "date": "2021-10-04T16:00:00.000Z"}';

let wrongWay = JSON.parse(meetingJSON);
wrongWay; // {title: 'Conference', date: '2021-10-04T16:00:00.000Z'} 可以看到date的值是字符串

let meetingObj = JSON.parse(meetingJSON, function(key, value) {
return (key === 'date') ? new Date(value) : value;
});

meetingObj; // {title: 'Conference', date: Mon Oct 04 2021 17:00:00 GMT+0100 (British Summer Time)}
meetingObj.date.getDate(); // 可以正常运行

总结

  • JSON是一种数据格式
  • JSON支持object, array, string, number, boolean, null
  • JavaScript提供序列化(serialize)成JSON的方法JSON.stringify和解析JSON的方法JSON.parse
  • 如果一个对象有toJSON方法,那么JSON.stringify会自动调用