赞
踩
对于函数型的字符串,我们想要将其转换为一个函数然后执行,有2种常用的方法。
eval()
具有可以解析表达式的特性,所以可以利用这一特性将字符串解析为一个函数。
let funcStr = "function test(value){alert(value)}";
let test = eval("(false || "+funcStr+")");
test("函数能够执行");
这里
eval
实际是解析了表达式(false || function test(value))
但是需要注意的事
eval
可以解析任何字符串,这是不安全的,请尽量不要使用。
new Function ([arg1[, arg2[, ...argN]],] functionBody)
new Function()
只接受字符串参数,其可选参数为方法的入参,必填参数为方法体内容。function add(a, b) { retrun a + b; } //等价于 var add = new Function ('a', 'b', 'return a + b');
- 1
- 2
- 3
- 4
- 5
我们可以利用它最后的方法体参数,直接返回一个函数。那么执行这个新的创建函数后得到的就是我们需要的函数。
let funcStr = "function test(value){alert(value)}";
let funcTest = new Function('return '+funcStr);
funcTest()("函数也能够执行")
如果是一个完整的函数体,且其中函数体内未包含其他函数,那么可以使用new Function
或eval
来实现。
如果函数体内包含函数,那么包含的函数必须和被调用的函数位于同一作用域下。
如何保证调用函数和调用参数在统一作用域?有2种方案可以采取:
下面讲解如何用实例限制作用域。
this.属性名
获取。this._f
即可省略为_f
;以let exp = _f("defaultStr")(_f("DFormat")(reportDate,'YYYY-MM-DD'))
字符串函数为例。
其中_f为一个函数,reportDate为一个变量
如果直接使用eval(exp)
,会报错_f is not defined
,因为默认情况下在严格模式下_f的作用域为undefined。
此时你可以设置window为作用域,例如:
//如果只是单纯的一个函数_f("DFormat")(reportDate,'YYYY-MM-DD')
//那么可与如下设置:
window._f = resolveFilter
expStr = `_f("DFormat")(reportDate,'YYYY-MM-DD')`
window.reportDate = "20191212";
let a = eval(expStr)
console.log(a)
将变量和方法绑定到window上,然后进行全局调用
但是上例是2个方法_f("defaultStr")(_f("DFormat")(reportDate,'YYYY-MM-DD'))
,函数调用时,立即执行
_f("DFormat")(reportDate,'YYYY-MM-DD')
,返回的结果不是一个函数,导致调用_f("defaultStr")
时,_f
方法被第二个函数的执行结果覆盖了,不再是一个方法了,所以不能继续执行。
要解决方法覆盖问题,那么方法就不能被定义为属性,而应该是原型,利用继承的特性解决该问题。
实例解决方案
//注册filter export const resolveFilter = (id) => { if (typeof id !== 'string') { return id; } else { return filters[id]//返回一个函数 } } //创建实例对象 export function createExpInstance(paramsEntity) { for (let key in paramsEntity) { this[key] = paramsEntity[key] } } createExpInstance.prototype._f = resolveFilter; createExpInstance.prototype.getValue = function (exp) { let code = `return (()=>{with (this) {return ${exp}}})()`; try { let func = new Function(code); let currentFunc = func.bind(this);//绑定函数this指向,严格模式下this为undefined,非严格模式为window return currentFunc(); } catch (err) { // console.log(err) } } let expInstance = new createExpInstance(paramsEntity); let expValue = expInstance.getValue(expStr);
with(this)
虽然是个不推荐属性,但是用在这里恰到好处,让我们省略了this的书写,从而直接利用实例属性和方法。
如果没有with(this)
,code
应为:
return (()=>{return this._f("defaultStr")(this._f("DFormat")(this.reportDate,'YYYY-MM-DD'))})()
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。