在使用JSON.stringify()方法将js对象转为字符串时,如果有循环引用,那么会报错,这个的解决。
JSON.stringify虽然比较常用,但是还有某些细节是我们不知道的,参见MDN文档
引用对象的解法:
const cache = []
JSON.stringify(stat, (key, value) => {
if (cache.indexOf(value) !== -1) {
return;
}
cache.push(value);
})
对比eval与new Function
eval是一个普通的函数,主要作用是动态解析和执行字符串,通过它可以将String变成可以执行的代码,与这个类似的有 new Function,setTimeout、setInterval
对比
- window.eval和new Function都是全局作用域的,即他们只能调用**全局变量**;
- eval是局部函数,即他可以调用其**父函数的局部变量**。
特点Function
- 注意由于new Function内访问全局作用域的变量,对于浏览器环境在当前文件的最外层就是全局作用域,但是对于node.js环境就会有问题,nodejs里面的new Function访问的全局作用域global,而文件内最外层的是输入当前模块的,这里需要额外注意一下。
- new Function() 与 Function()是等价的。
示例
var a = 10;
var b = 20;
var test = function () {
var b = 30;
return function (){
return a + b + c
}
}
var a = 1;
var b = 10;
var test = function () {
var b = 30;
return Function("", "return a + b")
}
var d = test()
d()
// 11
// node下运行会报错,a 未定义
var a = 1;
var b = 10;
var test = function () {
var b = 30;
eval("!function _ (c){ console.log(a + b +c)}(40)") //71
Function("c", "console.log(a + b +c)")(40) // 51
}
test()
// eval
var a = 0;
console.log(eval("var a = 10; a")) //10
console.log(a) //10
// new Function()
var b = 0;
console.log((new Function("var b = 10;return b"))()) // 10
console.log(b) // 0
// eval可以访问全局作用域的局部作用域
var c = 2;
function func1 (){
var b = 1;
return eval("c + b")
}
console.log(func1()) //3
// window.eval 只可以访问全局作用域
var c = 2;
function func1 (){
var b = 1;
return window.eval("c + b")
}
console.log(func1()) // ReferenceError: b is not defined
// new Function 只能访问全局作用域的变量
var d = 2;
function func1 (){
var e = 1;
return (new Function("return d + e"))()
}
console.log(func1()) // Uncaught ReferenceError: e is not defined
// eval 只在被直接调用并且调用函数就是 eval 本身时,才在当前作用域中执行
// code 1
var foo = 1;
function test() {
var foo = 2;
eval('foo = 3');
return foo;
}
test(); // 3
foo; // 1
// code 2
var foo = 1;
function test() {
var foo = 2;
var bar = eval;
bar('foo = 3');
return foo;
}
test(); // 2
foo; // 3
// 与code 2等价
var foo = 1;
function test() {
var foo = 2;
window.foo = 3;
return foo;
}
test(); // 2
foo; // 3
// 与code2 等价
var foo = 1;
function test() {
var foo = 2;
eval.call(window, 'foo = 3');
return foo;
}
test(); // 2
foo; // 3
- new Function 定义函数相比于其他的定义方式,执行速度慢。
- eval 只在被直接调用并且调用函数就是 eval 本身时,才在当前作用域中执行。
- eval可以执行传递给他的任意代码,如果代码未知,或者存在隐患时,所以可能会存在安全隐患。XSS
- 无法打断点进行调试
- 代码压缩混淆时不友好,会报错。
- 可读性差
- 浏览器有快编译和慢编译,快编译用于编译稳定的和可预测的代码,对于eval这样的,明显是不可预测的,所以速度会慢。
- 对使用者要求较高
相关资料:
- 关于eval与new Function
-
作用
在 use strict 模式下函数作用域内获得全局this对象(window)
- 在开发一些类库的时候可能会用到,比如webpack等之类的工具
babel在进行代码转换时,将其编译成es5时会用到
var _globals = (function(){ return this || (0,eval)("this"); }());
JavaScript取整数的方法
Math.floor
- Math.ceil
- ~~ 与 Math.floor效果相同
函数怎么判断是否是new调用
function People() {
if (this instanceof People) {
console.log("new 调用")
} else {
console.log("function 调用")
}
}