提问人:Jonathan Plumb 提问时间:7/22/2022 更新时间:7/23/2022 访问量:74
Javascript eval() 行为奇怪
Javascript eval() acting strange
问:
我正在创建自己的消息框(正常的“确定”对话框和“是/否”对话框),这些对话框可以在我的网站上弹出。当用户单击“确定”或“是/否”时,将调用使用 eval() 执行的回调。OK 回调工作正常,但我似乎无法让 Yes/No 回调工作。
我将首先显示 OK messageBox 代码,然后显示 yesNoBox 代码。
function messageBox(msg, onClose = null) {
var id = sessionStorage.getItem('messageIndex');
if (id === null || id === 'undefined') id = "0";
sessionStorage.setItem('messageIndex', parseInt(id) + 1);
sessionStorage.setItem('mb' + id, msg);
sessionStorage.setItem('mb' + id + "_onClose", onClose);
var code = localStorage.getItem('mb_ok');
if (code === null || code === 'undefined') request('GET ui/mb_ok.html?id=' + id, 'messageBoxResponse');
else {
var start = code.indexOf('mb_ok') + 'mb_ok'.length;
var end = code.indexOf('"', start);
var i = code.substring(start, end);
code = code.replace('mb_ok' + i, 'mb_ok' + id);
messageBoxResponse(code);
}
}
request('GET ui/mb_ok.html?id=' + id', 'messageBoxResponse') 使用 WebSockets 检索 messageBox HTML。服务器返回具有唯一 messageBox ID 的 HTML 并调用 messageBoxResponse()。
function messageBoxResponse(response) {
var start = response.indexOf('mb_ok') + 'mb_ok'.length;
var end = response.indexOf('"', start);
var i = response.substring(start, end);
var id = parseInt(i);
var msg = sessionStorage.getItem('mb' + id);
$('#stage').append(response);
$('#mb_ok' + id + '_body').html(msg);
var onClose = sessionStorage.getItem('mb' + id + '_onClose');
if (onClose !== null || onClose !== 'undefined') {
$('#mb_ok' + id).on('destroyed', eval(onClose));
}
document.activeElement.blur();
}
测试代码:
messageBox("This is my message box", () => { alert("BOX CLOSED!"); });
当我点击“确定”时,我得到:
YesNoBox 代码几乎相同,但同时具有 onYes 和 onNo 回调。
function yesNoBox(msg, onYes, onNo) {
var id = sessionStorage.getItem('mb_yesno_index');
if (id === null || id === 'undefined') id = "0";
sessionStorage.setItem('mb_yesno_index', parseInt(id) + 1);
sessionStorage.setItem('mb_yesno' + id, msg);
sessionStorage.setItem('mb_yesno' + id + '_onYes', onYes);
sessionStorage.setItem('mb_yesno' + id + '_onNo', onNo);
var code = localStorage.getItem('mb_yesno');
if (code === null || code === 'undefined') request('GET ui/mb_yesno.html?id=' + id, 'yesNoBoxResponse');
else {
var start = code.indexOf('mb_yesno') + 'mb_yesno'.length;
var end = code.indexOf('"', start);
var i = code.substring(start, end);
code = code.replace('mb_yesno' + i, 'mb_yesno' + id);
yesNoBoxResponse(code);
}
}
yesNoBoxResponse() 函数几乎相同,但增加了检查以确定是否选择了 yes 或 no:
function yesNoBoxResponse(response) {
var start = response.indexOf('mb_yesno') + 'mb_yesno'.length;
var end = response.indexOf('"', start);
var i = response.substring(start, end);
var id = parseInt(i);
var msg = sessionStorage.getItem('mb_yesno' + id);
$('#stage').append(response);
$('#mb_yesno' + id + '_body').html(msg);
$('#mb_yesno' + id).on('destroyed', () => {
var answer = sessionStorage.getItem('mb_yesno' + id + '_answer');
if (answer === null || answer === 'undefined') {
errorBox('INTERNAL SERVER ERROR: dev.js@' + new Error().lineNumber);
} else {
var onYes = sessionStorage.getItem('mb_yesno' + id + '_onYes');
var onNo = sessionStorage.getItem('mb_yesno' + id + '_onNo');
alert('onYes = ' + onYes + '\n\nonNo = ' + onNo);
if (onYes === null || onYes === 'undefined') onYes = 'errorBox("SERVER ERROR");';
if (onNo === null || onNo === 'undefined') onNo = 'errorBox("SERVER ERROR");';
//alert("onYes = " + onYes + "\nonNo = " + onNo);
if (answer === 'YES') {
eval(onYes);
} else {
eval(onNo);
}
}
});
document.activeElement.blur();
}
现在问题来了。eval(onYes) 和 eval(onNo) 将不起作用,即使代码正确。YesNo 框确实按预期关闭,但 eval() 都没有触发。
这是我打电话时看到的内容
yesNoBox("This is my YESNO box.", () => { alert("YES CLICKED"); }, () => { alert("NO CLICKED"); });
(注意:我添加了alert('onYes = ' + onYes + '\n\nonNo = ' + onNo);只是为了表明onYes和onNo确实保留了正确的代码)
这是该警报,在变量中显示正确的代码:
但是 Yes 和 No 实际上都没有用 eval() 触发。调试器不会显示任何问题。一切运行良好,但 YesNo 框只是关闭而不触发任何回调。
对不起,这篇文章很长,但我想确保我在这里涵盖了我的基础。有什么想法吗?
答:
多亏了评论,我才能够解决问题。我把代码改成了:
if (answer === 'YES') {
eval(onYes)();
} else {
eval(onNo)();
}
在“eval(...)”之后添加“()”解决了这个问题。
评论
只需使用带有对象的数组即可。您可以使用 id 来获取对象,并且在执行函数时不需要 eval。
var myCallbacks = [];
function yesNoBox(msg, onYes, onNo) {
const currentId = myCallbacks.length;
myCallbacks.push({
onYes,
onNo
});
//this is just to show you, I know it is not the same, faking a response
window.setTimeout(() => yesNoBoxResponse(`mb_yesno${currentId}"`), Math.ceil(4000 * Math.random()));
}
function yesNoBoxResponse(response) {
var start = response.indexOf('mb_yesno') + 'mb_yesno'.length;
var end = response.indexOf('"', start);
var i = response.substring(start, end);
var id = parseInt(i);
var data = myCallbacks[id];
data.onYes();
data.onNo();
myCallbacks[id] = undefined;
}
yesNoBox('xxxxxx', ()=>console.log('yes 1'), ()=>console.log('no 1'));
yesNoBox('xxxxxx', ()=>console.log('yes 2'), ()=>console.log('no 2'));
yesNoBox('xxxxxx', ()=>console.log('yes 3'), ()=>console.log('no 3'));
使用对象而不是数组
var myCallbacks = {};
let currentKey = 0;
function yesNoBox(msg, onYes, onNo) {
const currentId = currentKey++;
myCallbacks[currentId] = {
onYes,
onNo
};
//this is just to show you, I know it is not the same, faking a response
window.setTimeout(() => yesNoBoxResponse(`mb_yesno${currentId}"`), Math.ceil(4000 * Math.random()));
}
function yesNoBoxResponse(response) {
var start = response.indexOf('mb_yesno') + 'mb_yesno'.length;
var end = response.indexOf('"', start);
var id = response.substring(start, end);
var data = myCallbacks[id];
data.onYes();
data.onNo();
delete data[id];
}
yesNoBox('xxxxxx', ()=>console.log('yes 1'), ()=>console.log('no 1'));
yesNoBox('xxxxxx', ()=>console.log('yes 2'), ()=>console.log('no 2'));
yesNoBox('xxxxxx', ()=>console.log('yes 3'), ()=>console.log('no 3'));
评论
myCallbacks
Map
mb_yesno
delete
感谢评论,我已经解决了我的问题并删除了 eval()。
我创建了自己的 Dictionary 类,其功能与 sessionStorage 几乎相同,但现在都是本地的。
函数 messageBox() 现在是
function messageBox(msg, onClose = null) {
var id = sessionStorage.getItem('messageIndex');
if (id === null || id === 'undefined') id = "0";
sessionStorage.setItem('messageIndex', parseInt(id) + 1);
mb_dictionary.setItem('mb' + id + '_msg', msg);
mb_dictionary.setItem('mb' + id + '_onClose', onClose);
request('GET ui/mb_ok.html?id=' + id, 'messageBoxResponse');
}
函数 messageBoxResponse() 现在是
function messageBoxResponse(response) {
var start = response.indexOf('mb_ok') + 'mb_ok'.length;
var end = response.indexOf('"', start);
var i = response.substring(start, end);
var id = parseInt(i);
var msg = mb_dictionary.removeItem('mb' + id + '_msg');
$('#stage').append(response);
$('#mb_ok' + id + '_body').html(msg);
var onClose = mb_dictionary.removeItem('mb' + id + '_onClose');
if (onClose !== null && onClose !== 'undefined') {
$('#mb_ok' + id).on('destroyed', onClose);
}
document.activeElement.blur();
}
类似地,函数 yesNoBox() 现在是:
function yesNoBox(msg, onYes, onNo) {
var id = sessionStorage.getItem('messageIndex');
if (id === null || id === 'undefined') id = "0";
sessionStorage.setItem('messageIndex', parseInt(id) + 1);
mb_dictionary.setItem('mb' + id + '_msg', msg);
mb_dictionary.setItem('mb' + id + '_onYes', onYes);
mb_dictionary.setItem('mb' + id + '_onNo', onNo);
request('GET ui/mb_yesno.html?id=' + id, 'yesNoBoxResponse');
}
函数 yesNoBoxResponse() 现在是:
function yesNoBoxResponse(response) {
var start = response.indexOf('mb_yesno') + 'mb_yesno'.length;
var end = response.indexOf('"', start);
var i = response.substring(start, end);
var id = parseInt(i);
var msg = mb_dictionary.removeItem('mb' + id + '_msg');
$('#stage').append(response);
$('#mb_yesno' + id + '_body').html(msg);
var onYes = mb_dictionary.removeItem('mb' + id + '_onYes');
var onNo = mb_dictionary.removeItem('mb' + id + '_onNo');
$('#mb_yesno' + id).on('destroyed', () => {
var answer = mb_dictionary.removeItem('mb' + id + '_answer');
if (answer === 'YES' && onYes !== null && onYes !== 'undefined') onYes();
else if (answer === 'NO' && onNo !== null && onNo !== 'undefined') onNo();
});
document.activeElement.blur();
}
现在一切正常!
评论
(()=>{/*logic*/})();
onYes()
onClose()