开发过程中遇到一个问题:将字符串'false'和'true'转为布尔值
假设这个变量名为 stringBoolean,值为‘true’,我第一时间想到的是利用严格等号:
stringBoolean === 'true' // true
但是这种方法略显low,于是往下探索,再遇差点被遗忘在我脑海中的欺骗词法机制--eval
用eval(...)可以帮我达到转换字符串为布尔值的目的
eval('true') // true
了解eval
eval(...)函数接收一个字符串为参数,将其中的内容视为在书写时就存在于程序中这个位置的代码,我们可以根据eval的语意理解为它是通过欺骗,假装成在词法期就存在于当前代码位置来运作的
function foo(str, a) {
eval(str);
console.log(a, b)
}
const b = 2
foo('let b = 3', 1); // 1, 3
但是在严格模式中,eval(...)在运行时有自己的词法作用域,所以在其中的声明无法修改所在的作用域。如下所示:
function foo(str) {
'use strict';
eval(str); // ReferenceError: a is not defined
console.log(a,)
}
foo('let a = 2')
new Function(...) 函数的行为也很类似,它最后一个参数可以接收代码字符串,并将其转化为动态生成的函数。这种构建函数的语法比eval(...)略微安全一些。所以同样我们使用new Function(...) 函数也能达到我的目的
(new Function('', `return ${stringBoolean}`)) () // true
为什么不推荐使用eval
eval(...)除了在严格模式下会被影响外,最主要的就是会影响性能。
JavaScript引擎会在编译阶段进行数项性能优化。其中有些优化依赖于能够根据代码的词法进行静态分析,并且预先确定所有变量和函数的定义位置,才能在执行过程中快速找到标志符。标志符--其实就是我们平时所说的变量。
当引擎在代码中发现eval(...), 它只能简单的假设关于标志符位置的判断都是无效的,因为无法在词法分析阶段明确的知道eval(...)会接收到什么代码。
简而言之eval(...)的副作用就是引擎无法在编译时对作用域查找进行优化,因为引擎只能谨慎的认为这样的优化是无效的,从而导致代码运行变慢。
回到最初的问题
根据eval对性能的影响,所以它很自然的会在项目中被禁止使用,new Function(...) 也同样不被允许;
再三探索,JSON.parse(...)可以实现我想要的效果;
好吧,既然不推荐使用,那为什么要这么大幅篇章的介绍呢? 因为好不好使先不管,探索精神不能少呀。就像我们妹子买衣服,穿不穿先不管,购物的体验不能少,哈哈哈哈!
欢迎指正