Динамическое создание функций в JS
Я создаю движок AI для JS-игры, и он создан из конечных машин. Я загружаю количество состояний и их значения переменных из XML. Я также хочу загрузить поведение, и поскольку у меня нет времени на создание языка сценариев, я подумал, что было бы неплохо "вставить" JS-код на внешние файлы (внутри узлов XML) и выполнить его на спрос.
Что-то вроде этого
<evilguy1>
<behaviour>
this.x++;
</behaviour>
<behaviour>
this.y++;
</behaviour>
</evilguy1>
Что-то вроде этого:
function behaviour_1(){
this.x++;
}
function behaviour_2(){
this.y++;
}
Мой вопрос: теперь, когда у меня загружен код, как его выполнить? Я хотел бы создать функцию с уникальным именем для каждого кода "node", а затем вызвать их из логики игры, но я не знаю, возможно ли это (поскольку вы можете загрузить больше кода JS из HTML, вы также должны быть в состоянии сделать это из JS-кода, нет?). Если нет, есть ли подобное решение? Спасибо заранее!
(PS: чем меньше зависит от внешней библиотеки, тем лучше)
Изменить 1:
Хорошо, теперь я знаю, как создавать функции, содержащие код
window[classname] = function() { ... };
Ответы
Ответ 1
Ну, вы можете использовать конструктор Function
, как в этом примере:
var f = new Function('name', 'return alert("hello, " + name + "!");');
f('erick');
Таким образом вы определяете новую функцию с аргументами и телом и присваиваете ее переменной f. Вы можете использовать hashset и хранить много функций:
var fs = [];
fs['f1'] = new Function('name', 'return alert("hello, " + name + "!");');
fs['f1']('erick');
Загрузка xml зависит от того, запущена ли она на браузере или сервере.
Ответ 2
Чтобы продлить ответ Ericks о конструкторе Function.
Конструктор Function создает анонимную функцию, которая при ошибке выполнения будет печатать анонимную для каждой функции (созданной с помощью функции) в стеке вызовов. Что может сделать отладку сложнее.
Используя служебную функцию, вы можете динамически называть созданные вами функции и обходить эту дилемму. Этот пример также объединяет все тела каждой функции внутри массива функций в один, прежде чем возвращать все как одну именованную функцию.
const _createFn = function(name, functions, strict=false) {
var cr = `\n`, a = [ 'return function ' + name + '(p) {' ];
for(var i=0, j=functions.length; i<j; i++) {
var str = functions[i].toString();
var s = str.indexOf(cr) + 1;
a.push(str.substr(s, str.lastIndexOf(cr) - s));
}
if(strict == true) {
a.splice(1, 0, '\"use strict\";' + cr)
}
return new Function(a.join(cr) + cr + '}')();
}
A загорается о конструкторе Function:
Функция, определяемая выражением функции, наследует текущий объем. То есть, функция образует замыкание. С другой стороны, функция, определенная конструктором Function, не наследует никакой области кроме глобальной области (которую наследуют все функции).
источник: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Differences
Ответ 3
Предполагая, что у вас есть массив имен узлов и параллельный массив тел функций:
var functions = {};
var behaviorsNames = ['behavior1', 'beahvior2'];
var behaviorsBodies = ['this.x++', 'this.y++'];
for (var i = 0; i < behaviorsNames.length; i++){
functions[behaviorsNames[i]] = new Function(behaviorsBodies[i]);
}
//run a function
functions.behavior1();
или как глобалы:
var behaviorsNames = ['behavior1', 'beahvior2'];
var behaviorsBodies = ['this.x++', 'this.y++'];
for (var i = 0; i < behaviors.length; i++){
window[behaviors[i]] = new Function(behaviorsBodies[i]);
}