JavaScript 更改 eval 中的 this
开端
最近想实现一个小功能,通过一个字符串在对象上任意访问属性,还要支持表达式计算,前者可以直接通过属性访问器实现,但是要支持表达式计算,就得使上咱们的 eval 函数了。
看解决方案直接拉到文章底部。
然后直接踩坑。
众所周知 Function.prototype.call
和 Function.prototype.apply
方法可以在指定的上下文中调用函数。(JS 中的 this 只与被调用时的上下文有关)
咱马上就想出了代码,大概长这样:
1 |
|
然后发现代码一直达不到效果,一番调试之后发现了其中的大坑。
初探
查了一下网上也少有文章提及 eval 函数中 this 的问题,大概是因为只有垃圾程序员才用 eval 这种不安全的函数吧。(x)
连 mdn web docs 也只是提及了一句:
如果你间接的使用
eval()
,比如通过一个引用来调用它,而不是直接的调用eval
。从 ECMAScript 5 起,它工作在全局作用域下,而不是局部作用域中。
可 Function.prototype.call
和 Function.prototype.apply
算是间接调用吗?
可它们都是 naive native code ,咱也不知道,咱也不敢问。那就来调试康康。
现象
根据 mdn web docs 的说法,间接调用的方式会让 eval 的 this 跳转到全局作用域,看样子 Function.prototype.call
和 Function.prototype.apply
也是间接调用的一种。
解决
既然不能间接调用 eval,而直接调用 eval 取决的是 eval 所在位置的 this,那咱们是不是可以将 eval 的调用封装在一个函数中,再通过 Function.prototype.call
给这个函数指定 this,让这个带有 this 的函数去执行 eval 呢?
还真行。
这样就可以成功在调用 eval 的时候指定 this 辣。