小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前言
我们平时写前端代码的时候,函数都是提前编写好的。
今天我们就聊聊到到动态解析和执行函数,来点不一样的!!!!
动态解析和执行函数两种方式
evalnew Function
eval
函数会将传入的字符串当做 JavaScript 代码进行执行
简单计算:
eval(`2+2`) // 4
代码段:
var a = 10;
eval(`if (a >10) {console.log("大于10")}else console.log("小于等于10")`)
// 小于等于10
可以看到,eval是能访问当创建时所在的作用域的变量的。
字符转Json
在JSON.parse之前,我们常用eval把字符串转为对象
eval("({a:1, b:2})")
// {a: 1, b: 2}
可以简单封装一下:
function parseJSON(str){
return eval("(" + str + ")")
}
parseJSON("({a:1, b:2})")
// {a: 1, b: 2}
实际上setTimout的第一个参数,也是可以传入字符串的
setTimeout("console.log('好啊')", 1000)
// 好啊
其背后的工作机制就是 eval, 你可以用CSP禁止eval后再尝试,就知道了。
会爆出错误来!
eval的this
eval的this是和当前执行的上下文挂钩的,我们一起看看
var person = {
getName(){
console.log("this", eval("this"))
}
}
person.getName()
// {getName: ƒ}
window.eval("this")
// Window {window: Window, self: Window, document: document, name: '', location: Location, …}
所以直接调用eval和调用window.eval的区别是很大的。
new Function
语法
new Function ([arg1[, arg2[, ...argN]],] functionBody)
前面是参数名,最后一个是函数体
参数名和name
var sum = new Function("num1", "num2", "return num1+num2");
sum(1, 2);
// 3
console.log("name", sum.name);
// anonymous
sum.name = "sum"
console.log("name", sum.name);
// anonymous
我们自定义了一个加法函数, 其属性name为anonymous, 这个和空字符串还有区别。
我们一起看看空函数名的函数。
var person = {
name: "Tom"
};
person.getName = function (){
return this.name
}
console.log("name:", person.getName.name);
// name:
name为anonymous不等于name为""。
this属性
var sum = new Function("num1", "num2", `
console.log("this",this);
return num1+num2
`);
sum(1,2)
// Window {window: Window, self: Window, document: document, name: '', location: Location, …}
var person = {
getName: new Function(` console.log("this",this);`)
}
person.name()
// this {getName: ƒ}
var person2 = {
getName(){
return (new Function(`console.log("this:", this)`))()
}
}
person2.getName()
// this: Window {window: Window, self: Window, document: document, name: '', location: Location, …}
var getName = function() {
var nameXX = "tom";
return new Function("return nameXX")()
}
getName()
// Uncaught ReferenceError: nameXX is not defined
可以看到 new Function全局环境,因此在运行时它们只能访问全局变量和自己的局部变量,不能访问它们被 Function 构造器创建时所在的作用域的变量。
小结
- eval是恶魔,尽量不适用
- new Function更加安全,性能更加好,
不能访问它们被Function构造器创建时所在的作用域的变量。eval()通常比其他替代方法更慢,因为它必须调用 JS 解释器,而许多其他结构则可被现代 JS 引擎进行优化。
今天你收获了吗?