在修改一个问题的时候,发现在竟然用eval计算数组的和,不知道当时为什么会这样写(有点不过脑子),不过eval尽量不要使用,在MDN有2个不建议使用eval的建议:
如果要使用evel,可以使用Function进行替代,在MDN说Function比eval快,在后面的测试中,Function并没有比eval快很多.
function generateRandomArray(len) {
let arr = [];
for (let i = 0; i < len; i++) {
let value = Math.floor(Math.random() * len * 10);
arr.push(value);
}
return arr;
}
function test() {
let sumArr = [];
let randomArray = generateRandomArray(16);
for (var i = 0, len = randomArray.length; i < len; i++) {
//处理其他的逻辑
sumArr.push(randomArray[i]);
}
let expression = sumArr.join('+');
let sum = eval(expression); //使用eval计算 '1+2'表达式
console.log(expression);
console.log(sum);
}
看一下结果:
JavaScript使用eval计算表达式
先说说test函数中有哪些问题:
1) 使用eval计算表达式
2) 使用sumArr数组,多增加内存的使用,计算数组内值的和,没必要增加一个数组.
1) 最直接的方式,直接在for循环中进行计算
2) 使用JavaScript中reduce函数计算.
3) 使用Function代替eval函数计算.
来测试这几种方式,那个性能比较好.
function generateRandomArray(len) {
let arr = [];
for (let i = 0; i < len; i++) {
let value = Math.floor(Math.random() * len * 10);
arr.push(value);
}
return arr;
}
function evalTest(randomArray, testLen) {
let sum = 0;
let sumArray = [];
console.time('eval ' + testLen);
for (var i = 0, len = randomArray.length; i < len; i++) {
sumArray.push(randomArray[i]);
}
sum = eval(sumArray.join('+')); //使用eval计算表达式
console.timeEnd('eval ' + testLen);
console.error('eval:' + sum);
}
function forTest(randomArray, testLen) {
let sum = 0;
console.time('for ' + testLen);
for (var i = 0, len = randomArray.length; i < len; i++) {
//最简单直接的方式,直接求和运算
sum += randomArray[i];
}
console.timeEnd('for ' + testLen);
console.error('for:' + sum);
}
function readuceTest(randomArray, testLen) {
let sum = 0;
console.time('reduce ' + testLen);
sum = randomArray.reduce((previousValue, currentValue) => {
return previousValue + currentValue
}, 0); //使用reduce
console.timeEnd('reduce ' + testLen);
console.error('reduce:' + sum);
}
function functionTest(randomArray, testLen) {
let sum = 0;
let sumArray = [];
console.time('function ' + testLen);
for (var i = 0, len = randomArray.length; i < len; i++) {
sumArray.push(randomArray[i]);
}
//使用Function
sum = new Function('"use strict"; return ' + sumArray.join('+') + ';')();
console.timeEnd('function ' + testLen);
console.error('function:' + sum);
}
function allTest() {
var testLenArray = [16, 64, 128];
for (var i = 0, len = testLenArray.length; i < len; i++) {
let randomArray = generateRandomArray(testLenArray[i]);
evalTest(randomArray, testLenArray[i]);
forTest(randomArray, testLenArray[i]);
readuceTest(randomArray, testLenArray[i]);
functionTest(randomArray, testLenArray[i]);
}
}
allTest();
先看看Edge浏览器执行结果:
使用Edge浏览器执行eval和Function性能测试
然后看看Firefox浏览器的执行结果:
使用Firefox浏览器执行eval和Function性能测试
通过测试结果得出:
1) 在循环内,直接求和的方式在数组长度不多的情况,性能最好
2) reduce在数组长度相对多之后,性能比for求值性能好
3) Function在性能上和eval半斤八两
个人能力有限,如果您发现有什么不对,请私信我
如果您觉得对您有用的话,可以点个赞或者加个关注,欢迎大家一起进行技术交流
val加密的终极用法
Eval加密,做为一种传统且古老的JS代码加密方法,相信很多人都知道。
例如这个在线Eval加密:
https://www.fairysoftware.com/js_jia_mi_eval.html
但这种Eval加密,其实并不能算真正的加密,只能算一种编码,可以被很容易的逆向得到原始代码。
但本文要介绍的,并非这种Eval加密。
而是借助Eval,并结合专业JS混淆加密所实现的,用这个方法加密得到的JS代码,安全强度非常高。
下面,进行演示:
例如一段JS代码:
function get_copyright(){
var domain = "jshaman.com";
var from_year = 2017;
var copyright = "(c)" + from_year + "-" + (new Date).getFullYear() + "," + domain;
return copyright;
}
console.log(get_copyright());
用jshaman(https://www.jshaman.com/)进行混淆加密:
得到如下加密代码:
如上图所示,虽然加密后的代码已经非常混乱。
但如果希望console、函数名也“消失”,则可以借且eval。
将原始代码改造成以下形式:
var str = `
function get_copyright(){
var domain = "jshaman.com";
var from_year = 2017;
var copyright = "(c)" + from_year + "-" + (new Date).getFullYear() + "," + domain;
return copyright;
}
console.log(get_copyright());
`
eval(str)
说明:将原来的代码整体做为字符串都包裹在了eval中执行。
再对上面的代码进行混淆加密:
加密生成了新的代码:
在新生成的代码中,console、函数名,都找不到了,原始代码的线索彻底消失。
因为在用JShaman混淆加密时,把原始代码整体当做字符串加密了,原本代码中的语法关键字、系统变量、函数名等等,全被加密了。
通常来说,直接用JShaman加密得到的JS代码,已可满足99%的需求。但如果遇到特别的场合、加密强度要求的极高,那么,可以用本文讲述的方法,对JS代码改造再进行混淆加密。但需注意:转成字符串的代码量不可太大。
val()的使用
eval() 函数可将字符串转换为代码执行,并返回一个或多个值
eval调用时,实例为eval( "( javascript代码 )" )
eval()的返回值
eval()的返回值遵循以下规则:
1.如果eval()的参数不是字符串,那么eval()将直接返回参数。
2.如果eval()的参数是字符串,那么eval()将这个字符串解析成代码后进行执行,并返回最后一行代码执行的结果。
3.如果字符串无法解析成合法的代码,eval()将抛出SyntaxError错误。
举例1(eval的参数不是字符串):
运行结果(谷歌浏览器测试):
举例2(eval的参数是字符串):
运行结果(谷歌浏览器测试):
当然,如果不使用eval()方法,上面的代码可以使用匿名函数写
举例3(字符串无法解析成合法的代码):
运行结果(谷歌浏览器测试):此时可以看到 谷歌浏览器控制台报错
eval()的兼容性问题
IE6/7/8不兼容
使用IE8来测试代码:
没有弹出框,控制台报错:
解决方法:
a)var s = "[function(){alert('Test!')}][0]";
b)var s = "0?0:function(){alert('Test!')}";
当然这个解决方法是从国外论坛里面找到(网站:http://stackoverflow.com/questions/6807649/problems-with-ie9-javascript-eval)
大意是:这在JScript解释器里面是一个bug,它不会出现在IE9除非你使用混杂模式或兼容来看。IE8错误将这个函数表达式解释为函数的声明,使得它没有任何的返回值。所以你可以写成其他比较典型的表达式,从从而在JScript解释器中构成一个表达式
那么我们就知道IE6/7/8使用JScrip解释器来解析eval()把参数当初函数声明,没有返回值,所以我么可以把eval()函数里面的字符串代码写成一个表达式,即可以写成:
[function(){alert('Test!')}][0] 或 0?0:function(){alert('Test!')}
改代码:
在IE8里面测试结果:
最后利用ietester工具测试在IE6也同样没有问题。
*请认真填写需求信息,我们会在24小时内与您取得联系。