Я неправильно в первом сообщении написал задачу. Там я намного всё упростил, чтобы попонятнее, но вышло наоборот. Пример выше рабочий. У меня же немного иначе это происходит через промисы, примерно так:
Опять же я тут всё сильно упростил. Смысл в том, что у меня в начале, в хедере страницы стоит загрузчик модулей, запускается скрипт и загружает указанные модули создав промис. В конце страницы пользовательские скрипты, которые запускаются в этом промисе после того как страница и все JS модули загружены.
Так вот нужен доступ к переменным промиса при new Function в модуле событий. Опять же мы не можем передавать переменные по цепочке промиса и в модули, т.к. заранее не знаем какие будут вообще переменные.
Теперь я лучше понимаю вашу задачу. Проблема в том, что переменные, объявленные внутри Promise (как aa в вашем примере), находятся в замкнутой области видимости этого Promise и недоступны для функций, создаваемых через new Function() позже.
В JavaScript существует фундаментальное ограничение: функции, созданные через new Function() , имеют доступ только к глобальной области видимости (например, window в браузере), но не к локальным переменным или замыканиям.
Вот несколько возможных подходов к решению:
// Создаем глобальный объект для хранения данныхwindow.appContext = {};new Promise(function(resolve, reject){ // Сохраняем переменную в глобальный объект window.appContext.aa = 'AAA'; resolve('console.log(ee+window.appContext.aa)');}).then((sf)=>{ function Nf(){ return new Function('ee', sf) } let Fu = Nf(); Fu('BBB')})
2. Передавать контекст в виде объекта в обработчики:
new Promise(function(resolve, reject){ let aa = 'AAA'; // Передаем как код, так и данные для выполнения resolve({ code: 'console.log(ee+context.aa)', context: { aa } });}).then((data)=>{ function Nf(){ // Создаем функцию, которая примет контекст return new Function('ee', 'context', data.code) } let Fu = Nf(); Fu('BBB', data.context)})
3. Использовать паттерн "Внедрение зависимостей" для ваших модулей:
// Система модулейconst ModuleSystem = { modules: {}, context: {}, register(name, factory) { this.modules[name] = factory; }, setContext(contextData) { Object.assign(this.context, contextData); }, getModule(name) { if (!this.modules[name]) throw new Error(`Module ${name} not found`); return this.modules[name](this.context); }};// Регистрация модуля событийModuleSystem.register('events', (context) => { return { createHandler(code) { // Используем контекст при создании функции return new Function('event', 'context', code); }, bindHandler(element, eventName, handler) { element.addEventListener(eventName, (e) => { // Передаем контекст в обработчик handler(e, context); }); } };});// Использованиеnew Promise(function(resolve) { let aa = 'AAA'; // Добавляем aa в контекст ModuleSystem.setContext({ aa }); resolve();}).then(() => { // Получаем модуль событий с контекстом const events = ModuleSystem.getModule('events'); // Создаем обработчик const handler = events.createHandler('console.log(event + context.aa)'); // Привязываем обработчик events.bindHandler(document.getElementById('myElement'), 'click', handler);});
Ключевое здесь: вместо того, чтобы пытаться передать переменные в функцию напрямую, мы передаем объект контекста, который содержит все нужные переменные.
Это более чистый подход с архитектурной точки зрения, чем использование глобальных переменных.
Ничего не понятно на самом деле =) Но если че то не получается, значит не правильный подход и надо делать по другому, а не городить костыли =)
И на счет глобальных переменных, они получается срабатывают после основного кода?
Да, вы правы - если решение слишком сложное, значит подход стоит пересмотреть. Давайте разберемся в ситуации более четко.
По поводу глобальных переменных - они доступны в любой момент после их объявления. Проблема в том, что когда вы создаете функцию через new Function() , она имеет доступ только к глобальной области видимости, но не к локальной области, где была создана.
В примере:
let aa='AAA', sf='console.log(ee+aa)';function Nf(){ return new Function('ee',sf)}let Fu=Nf();Fu('BBB')
Переменная aa объявлена в глобальной области, но внутри new Function() она не видна, потому что функция, созданная через new Function() , имеет доступ только к глобальному объекту (window в браузере).
Вот более простой подход без костылей:
// Глобальные переменные должны быть свойствами глобального объектаwindow.aa = 'AAA'; // Для браузера, если это Node.js, то global.aa = 'AAA'let sf = 'console.log(ee+aa)';function Nf(){ return new Function('ee', sf)}let Fu = Nf();Fu('BBB'); // Теперь должно вывести "BBBAAA"
Главное различие: let aa = 'AAA' создает переменную в текущей области видимости, а window.aa = 'AAA' создает свойство глобального объекта, которое будет доступно внутри функции, созданной через new Function() .
Если хотите проще решить исходную задачу с обработчиками событий, стоит посмотреть в сторону использования системы событий, которая уже решает эту проблему (например, какой-нибудь EventEmitter паттерн).
Я понимаю вашу задачу - вам нужно создавать функции-обработчики событий для элементов с атрибутами, содержащими код, и при этом обеспечить доступ к глобальным переменным.
Проблема в том, что new Function() создает функцию в глобальной области видимости, но не имеет доступа к переменным из областей видимости, в которых она была создана (кроме глобальных).
Вот вариант решения:
// Создаем функцию, которая получит доступ к глобальному объектуfunction createFunctionWithGlobals(code, paramNames = [], paramValues = []) { // Получаем глобальный объект (window в браузере или global в Node.js) const globalObj = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this; // Собираем имена всех глобальных переменных const globalVarNames = Object.keys(globalObj) .filter(key => !['undefined', 'NaN', 'Infinity'].includes(key) && typeof key === 'string' && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key)); // Создаем массив со значениями этих переменных const globalVarValues = globalVarNames.map(name => globalObj[name]); // Объединяем параметры функции с глобальными переменными const allParamNames = [...paramNames, ...globalVarNames]; const allParamValues = [...paramValues, ...globalVarValues]; // Создаем функцию с доступом к глобальным переменным try { return new Function(...allParamNames, code).bind(null, ...allParamValues); } catch (e) { console.error("Ошибка при создании функции:", e); return () => console.error("Функция не была создана из-за ошибки:", e); }}// Пример использования:let aa = 'AAA';let sf = 'console.log(ee + aa)';// Создаем функцию с доступом к глобальным переменнымconst Fu = createFunctionWithGlobals(sf, ['ee']);// Вызываем функциюFu('BBB'); // Выведет "BBBAAA"
Что делает это решение:
Это позволит вашим динамически создаваемым обработчикам событий иметь доступ к любым глобальным переменным, которые существуют на момент создания функции.
Интересно, вернется ли трафик...
Что за скрипт?))
Самопис 😉
Последовал вашему совету😄https://kakaha.ru/
https://vc.ru/legal/1650856-vlasti-zadumalis-o-vvedenii-sbora-za-reklamu-v-internete-forbeshttps://www.forbes.ru/tekhnologii/525011-vlasti-gotovatsa-vvesti-novyj-sbor-za-reklamu-v-internete