模板字面量对我来说有点像 eval,它经常被引用为 using eval is a bad idea .
我不关心 performance of template literals ,但我担心注入(inject)攻击(以及我可能没有想到的其他安全问题)。
编辑
An example of something that feels odd to me
let ii = 1;
function counter() {
return ii++;
}
console.log(`${counter()}, ${ii++}, ${counter()}`);
哪些输出
1, 2, 3
模板文字在全局级别产生副作用。既可以通过函数,也可以直接。
编辑2
An example indicating the saferness of template literals
let ii = 1;
let inc = function() { ii++; }
console.log('Starting: ' + ii);
let input = prompt('Input something evil (suggestion: inc() or ii++)');
console.log(`You input: ${input}`);
console.log('After template literal: ' + ii);
eval(input);
console.log('After eval: ' + ii);
如果在提示时输入ii++
,它会记录
Starting: 1
You input: ii+=1
After template literal: 1
After eval: 2
编辑3
我已经开始研究 ECMAScript 规范
- 18.2.1 - Function Properties of the Global Object :: Eval (x)
- 注意它在全局对象上
- 请注意下一部分是关于 eval 的“运行时语义”
- 12.2.9 - Primary Expression :: Template Literals
- 注意这是一个表达式
- 注意下一节是关于 TemplateString 的“静态语义”
虽然我没有摸索细节,但感觉模板文字的指定比 eval 更安全。
最佳答案
与 eval
的一个区别是模板文字在编译时解析,而 eval
的参数仅在运行时解析,当 eval
被执行。
与此相关的是,eval
可以获得动态构建的参数,而模板文字是... literal:它不能存储为模板 变量,您可以动态构建、四处移动并最终解析:没有“模板变量”数据类型。标记函数实际上并没有获取模板变量作为参数,而是它的解析组件,这些组件在编译时是已知的。
一些例子
使用 eval
你可以遇到这种情况:
var code = prompt('enter some evil code');
eval(code);
但这对于模板文字是不可能的:
var literal = prompt('enter some evil template literal');
tag literal; // there is no data type or syntax for this.
`${literal}`; // and this just gives you the entered string.
什么是可能的,是这样的:
var str = prompt('enter some string');
tag`${str}`;
但这不会导致不需要的代码执行,至少不会比这更糟:
var str = prompt('enter some string');
myfunc(str);
任何函数调用都必须已经在模板文字中进行了字面编码。字符串变量的值不能改变它。模板文字无法调用变量函数。这:
`${func(str)}`;
...将调用func
,并且只调用那个函数。它由程序员选择。
一个相当邪恶的模板文字
话虽如此,这仍然是可能的:
var func = prompt ("enter some evil function name (suggestion: 'alert')");
var param = prompt ("now provide an argument for " + func);
`${window[func](param)}`;
但很明显,程序自愿开启了在全局对象上执行任何函数的可能性。那么确实,您正在接近 eval
的邪恶。
请注意,同样的效果可以通过以下方式实现:
window[name](param);
最邪恶的模板字面量
如评论所述,那么您不妨将此模板设为文字:
`eval(str)`;
...因此,邪恶的部分并不在模板文字中,而是您设计在其中的通用函数调用。为此,您不需要模板文字或 eval
,而是一个糟糕的程序员 ;-)
关于例子
你举了这个例子:
let ii = 1;
function counter() {
return ii++;
}
console.log(`${counter()}, ${ii++}, ${counter()}`);
这会执行您的 counter
函数,但与 eval
的区别在于字符串文字在设计时已经存在,并且无法在运行时构造.此代码旨在增加您的计数器,并且与以下代码没有本质区别:
console.log(counter() + ', ' + (ii++) + ', ' + counter());
编译时间
为了强调编译/运行时解析的区别,请注意您不能使用没有有效语法的模板文字来运行代码。
比较这两个脚本:
alert('press OK');
eval('alert("hello)');
和:
alert('press OK');
`${alert("hello)}`;
注意语法错误。第一个脚本只会在解析 eval
的参数时在运行时注意到语法错误,而第二个脚本甚至不会运行,并立即给出语法错误。
更准确地说,eval
执行一个新脚本,它有自己的编译和运行阶段。模板文字像其他代码一样被解析/编译。
关于javascript - ES6 模板文字比 eval 更安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37243791/