一、eval的基本概念
eval会将传入的字符串当作JS代码来执行,返回值是执行的结果,比如:
eval('2 + 2') //4
如果传入的参数不是字符串,eval会将参数原样返回:
eval(new String("2 + 2")) //返回一个包含"2+2"的字符串对象 String {"2 + 2"}
二、eval的实际用处
- 将字符串解析成对象
var str = JSON.stringify({a:1})
eval(str) // Uncaught SyntaxError: Unexpected token ':'
eval("(" + str + ")") // {a: 1}
eval(str)会报语法错误,是因为eval把传入的字符串参数"{"a":1}"当作表达式来求值,因为{"a":1}不是一个合法的表达式,因此会报出语法错误。JS中的表达式都有哪些类型,详见
表达式和运算符developer.mozilla.org
而第二句eval("(" + str + ")")不会报错,是因为({"a":1})是一个正确的表达式,在浏览器控制台执行这个表达式,得到的是{a: 1},这就是圆括号运算符的神奇之处。
你可能会问,已经有JSON.parse可以把字符串解析成对象了,为什么还会有用eval解析的应用场景呢?二者之间的区别是什么呢?
eval("({a: 1})") // {a: 1}
JSON.parse("({a: 1})") // Uncaught SyntaxError: Unexpected token ( in JSON at position 0
JSON.parse只能解析正确的JSON字符串,也就是说属性名也必须得用引号包裹,否则就会抛出异常。
而eval不仅可以解析正确的JSON字符串,还可以解析属性名不带引号的对象字符串,如果你的项目中有类似的应用需求,eval就能派上用场了。
2. 让函数里的代码在全局作用域中运行
通过eval执行的代码具有与eval相同的作用域,假设这样一个场景,通过ajax获得一段JS代码,需要在全局作用域中执行这段代码,但是这段代码的获取是在某个函数中,那么如何在eval的帮助下实现这个需求呢?
function test () {
var jsStr = ajax()
window.eval(jsStr)
}
test()
进一步写个demo验证下:
function test () {
var jsStr = "function fun(){return 1}"
window.eval(jsStr)
}
test()
fun() // 1
你可能会想问,JS中还有一个用法也能动态解析和执行JS字符串,那就是new Function(),那么二者之间的区别是什么呢?
eval中的代码执行时的作用域为当前作用域,它可以访问到函数中的局部变量,但是new Function执行时的作用域始终是全局作用域。
var a = 'global scope'
function fun(){
var a = 'local scope'
eval('console.log(a)') //local scope
;(new Function('','console.log(a)'))() //global scope
}
fun()
三、一道面试题
最后用一道面试题来检验上面的学习成果:实现一个JSON.parse
有两种方法:
- eval
function jsonParse (str) {
return eval("(" + str + ")")
}
2. new Function
function jsonParse (str) {
return (new Function('return' + str))()
}