JSON.stringify()
-
语法:
JSON.stringify(value, replacer, space)
-
value:是必选字段。就是你输入的对象,比如数组,类等
-
replacer:可选。它又分为2种方式,一种是数组,第二种是方法。
1、如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;如果该参数为 null 或者未提供,则对象所有的属性都会被序列化
2、如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理
-
space:可选,指定缩进用的空白字符串,用于美化输出
1)如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格
2)如果仅仅是字符串,就在每行输出值的时候把这些字符串附加上去。当然,最大长度也是10个字符
3)如果是一些转义字符,比如“\t”,表示回车,那么它每行一个回车
4)如果该参数没有提供(或者为 null),将没有空格。
JSON. parse()
-
语法:
JSON.parse(text, reviver)
-
text:必需, 一个有效的 JSON 字符串
-
Reviver:可选,转换结果的函数, 将为对象的每个成员调用此函数
1、当遍历到最顶层的值(解析值)时,传入 reviver 函数的参数会是空字符串 ""
2、函数的遍历顺序依照:从最内层开始,按照层级顺序,依次向外遍历
-
注:不允许用逗号作为结尾
eval()
-
语法:
eval(string)
-
string:一个表示 JavaScript 表达式、语句或一系列语句的字符串。表达式可以包含变量与已存在对象的属性。
-
返回值:返回字符串中代码的返回值。如果返回值为空,则返回 undefined。
-
转JSON注意点:使用eval来解析JSON格式字符串的时候,会将{}解析为代码块
1、在JSON格式的字符串前面拼接上 "var o =";
2、把JSON格式的字符串使用()括起来,就不会将{}解析为代码块,而是表达式。
1、非严格模式下直接调用 eval() 时,里面使用 var 声明的变量和使用 function 声明的函数会修改当前词法作用域,里面使用 let 和 const 声明的变量不会修改当前词法作用域,但是会在当前创建新的词法作用域。
/**
* 使用 var 声明的变量和 function 声明的函数修改了当前词法作用域。
* 在 inner 内部创建的变量 a 和函数 fnA 覆盖了外部的变量 a 和函数 fnA。
* 变量 a 和函数 fnA 在 inner 内没有被提升。
*/
(function () {
const a = 0;
function fnA() {
return 10;
}
(function inner() {
console.log(a); // 0
console.log(fnA()); // 10
eval('var a = 1; function fnA () { return 11; };');
console.log(a); // 1
console.log(fnA()); // 11
}());
}());
// 使用 const 和 let 声明的变量没有修改当前词法作用域,在当前创建了新的词法作用域。
// 在 eval() 外部无法访问变量 a 和 b。
(function () {
eval('const a = 2; let b = 3;');
console.log(a); // ReferenceError
console.log(b); // ReferenceError
}());
2、非严格模式下间接引用 eval() 时,会直接运行在全局环境中,里面使用 var 声明的变量和使用 function 声明的函数会修改全局词法作用域,里面使用 let 和 const 声明的变量不会修改全局词法作用域,但是会在全局环境创建新的词法作用域。
var g = 0;
(function () {
const g = 1, ev = eval;
function fnG() {
return 10;
}
ev('console.log(g)'); // 0
ev('var g = 2; function fnG () { return 11; };');
console.log(g); // 1
console.log(fnG()); // 10
}());
console.log(g); // 2
console.log(fnG()); // 11
3、严格模式下直接调用的 eval() 时,会在当前创建一个新的独立的词法作用域。
(function () {
const a = 0;
function fnA() {
return 10;
}
(function inner() {
'use strict';
console.log(a); // 0
console.log(fnA()); // 10
eval('var a = 1; function fnA () { return 11; };');
console.log(a); // 0
console.log(fnA()); // 10
}());
}());
4、严格模式下间接引用的 eval() 时(只有在 eval() 内的字符串里面开启严格模式时,字符串才会以严格模式执行),会在全局环境创建一个新的独立的词法作用域。
var m = 0;
(function () {
const m = 1, ev = eval;
function fnM() {
return 10;
}
ev('\'use strict\'; console.log(m)'); // 0
ev('\'use strict\'; var m = 2; function fnM () { return 11; };');
console.log(m); // 1
console.log(fnM()); // 10
}());
console.log(m); // 0
console.log(fnM()); // ReferenceError
5、使用 window.eval() 等同于间接引用 eval() 。
// 非严格模式下使用
var x = 0;
(function () {
const x = 1;
function fnX() {
return 10;
}
window.eval('console.log(x)'); 0
window.eval('var x = 2; function fnX () { return 11; };');
console.log(x); // 1
console.log(fnX()); // 10
}());
console.log(x); // 2
console.log(fnX()); // 11
// 严格模式下使用
var y = 0;
(function () {
const y = 1;
function fnY() {
return 10;
}
window.eval('\'use strict\'; console.log(y)'); // 0
window.eval('\'use strict\'; var y = 2; function fnY () { return 11; };');
console.log(y); // 1
console.log(fnY()); // 10
}());
console.log(y); // 0
console.log(fnY()); // ReferenceError
6、 eval() 中执行的代码只能调用 JS 解释器(Interpreter)来解释执行,无法被即时编译器(JIT Compiler)优化, eval() 中的执行的代码可能会导致 JS 引擎在已经生成的机器代码中进行变量查找和赋值,带来性能问题。
7、 eval() 使用不当可能会导致里面执行的字符串容易遭受恶意修改,带来安全问题(比如 XSS 攻击)。
8、使用 eval() 会干扰代码压缩工具的行为。代码压缩工具一般会将局部变量名重命名为更短的变量名(如 a 和 b 等),以便减小代码体积。当使用了 eval() 时,由于外部的局部变量可能会被 eval() 访问到,代码压缩工具便不会对可能会被 eval() 访问到的局部变量名进行压缩,会降低代码压缩率。
-
注:最好永远不要使用eval函数,它使用与调用者相同的权限执行代码。
-
如果你用 eval() 运行的字符串代码被恶意方修改,最终可能会在您的网页/扩展程序的权限下,在用户计算机上运行恶意代码。
-
更重要的是,第三方代码可以看到某一个 eval() 被调用时的作用域,这也有可能导致一些不同方式的攻击。相似的 Function 就不容易被攻击。