JS如何执行一个字符串代码?
1. eval
2. setTimeout
3. script
eval示例
var a = 'x'
function run(code){
var a = 'xx'
eval(code)
}
run('console.log(a)')
console.log('run')
// xx
// run
特点
- 从示例代码我们可以知道
eval
函数是同步执行 eval
的作用于取决于其调用时所在的作用域(示例代码所在run
函数中)
注意点
如果你间接的使用eval()
,比如通过一个引用来调用它,而不是直接的调用 eval。从 ECMAScript 5 起,它工作在全局作用域下,而不是局部作用域中。什么意思呢?
var a = 'x'
function run(code){
var a = 'xx'
const refer_eval = eval
refer_eval (code)
}
run('console.log(a)')
console.log('run')
// x
// run
可以看到如果我们没有直接使用eval
而通过引用调用则作用于为全局作用域!
eval缺点
- 不安全。如果你用
eval()
运行的字符串代码被恶意方(不怀好意的人)修改,你最终可能会在你的网页/扩展程序的权限下,在用户计算机上运行恶意代码。 - 效率低-1。
eval()
通常比其他替代方法更慢,因为它必须调用 JS 解释器,而许多其他结构则可被现代 JS 引擎进行优化。(引擎很难在解析时进行优化,因为它无法提前知道代码的结构和内容。) - 效率低-2。此外,现代 JavaScript 解释器将 JavaScript 转换为机器代码。这意味着任何变量命名的概念都会被删除。因此,任意一个 eval 的使用都会强制浏览器进行冗长的变量名称查找,以确定变量在机器代码中的位置并设置其值。
setTimeout示例
var a = 'x'
function run(code){
var a = 'xx'
setTimeout(code)
}
run('console.log(a)')
console.log('run')
// run
// x
特点
- 异步执行
- 作用域为全局作用域
script
var a = 'x'
function run(code){
var a = 'xx'
const script = document.createElement('script')
script.innerHTML = code
document.head.appendChild(script)
}
run('console.log(a)')
console.log('run')
// x
// run
特点
- 同步执行
- 全局作用域
Function
var a = 'x'
function run(code){
var a = 'xx'
new Function(code)();
}
run('console.log(a)')
console.log('run')
// x
// run
特点
- 同步执行
- 全局作用域
总结
- 四种方式可以动态执行js代码,eval、Function、Script、setTimeout
- eval低效,但是作用于能够指向其所在作用域。
- eval/script/Function都是同步执行,setTimeout是异步执行
- Function、scirpt、setTimeout和间接执行eval都是全局作用域名。直接执行eval是其所在作用于。