Использование косвенных вызовов на eval
Доступ к глобальным определениям const
и let
может быть выполнен с помощью косвенного вызова eval
. То есть сделайте eval
результатом выражения, разделенного запятыми, или сначала присвойте его переменной. Если синтаксический доступ не напрямую к встроенной функции eval
, это косвенный доступ, и косвенный доступ выполняется в глобальной области видимости.
Вы также можете установить глобальные переменные let
, создав скрипт для выполнения операции настройки.
"use strict";
let myVar = "global variable myVar";
console.log( myVar);
(function myLibrary() {
const myVar = "local variable myVar";
const indirectEval = eval;
var varName = "myVar";
console.log( eval(varName)); // direct call uses local scope
console.log( indirectEval(varName)); // indirect call uses global scope
var result = "\"updated global variable even though shadowed\"";
var js = varName + '=' + result;
indirectEval(js);
// but trying to define a new let variable doesn't attach to global scope
var js2 ='let letVar2 = "let variable two"';
indirectEval( js2);
})();
console.log( myVar)
console.log( "letVar2: " + typeof letVar2);
Чего вы не можете сделать, так это добавить переменную let
или const
в глобальную область, используя косвенный вызов eval: они являются объявлениями уровня блока, а код, который оценивает eval
, считается блоком - поэтому объявления отбрасываются при возврате (косвенный вызов) eval
.
PS. Это технический ответ. И да, я слышал, что «eval is evil» раньше, один или три раза.
Для доступа только для чтения с использованием жестко закодированных строк имен переменных (для предотвращения вставки кода) вы можете использовать шаблон:
(0,eval)("identifierString");
как например:
var x = 3;
const y = 7;
let z = 21;
{
const y = "shadow"
let z = 42;
console.log('x = ' + (0,eval)('x')); //x = 3
console.log('y = ' + (0,eval)('y')); //y = 7
console.log('z = ' + (0,eval)('z')); //z = 21
}
Непрямые и прямые звонки на eval
Прямой вызов eval
получает только значения глобальных переменных, которые не были затенены в области действия вызова. Это может ограничить выбор имен переменных или того, откуда можно сделать вызов в библиотеке.
Косвенный вызов выполняется в глобальной области видимости и может получить значение глобальных переменных независимо от затенения имен в библиотеке.
Создание нового объекта Function
из исходного текста и его вызов может стать альтернативой использованию косвенного вызова eval
на веб-странице. Однако разница во многом семантическая, а не одна лучше другой.
Вопросы
Если имя глобальной переменной (var
, let
, const
или class
идентификатор) поступает из пользовательского ввода, его действительно следует проверить на достоверность ( не все так просто ) или по крайней мере доступ к нему внутри блока try / catch для отлова использованных необъявленных идентификаторов или использования объявлений имен перед инициализацией.
Лично я бы порекомендовал найти альтернативы использованию строк имен глобальных переменных в целом. На ум приходят предоставление статического объекта пространства имен в библиотеке (например, myLibrary.data
) и обработка строковых значений, которые являются именами свойств объекта, или включение параметров объекта опции в вызовы библиотеки.