В большинстве реализаций JavaScript предоставляется возможность декомпилировать уже вычисленный код JavaScript. Такой процесс называется сериализацией, хотя для его обозначения употребляется также термин декомпиляция. Как правило, термин декомпиляция обозначает восстановление исходного кода из ассемблерного или байт-кода, что, очевидно, не подходит для JavaScript. Но помимо сериализации, у которой имеются свои семантические особенности, на самом деле не существует подходящего термина для обозначения данного процесса. Так, термин “развычисление” трудно вообще произнести, поэтому мы будем в дальнейшем пользоваться термином декомпиляция, признавая, что он не совсем подходит в данном контексте.
Какой бы сложной ни показалась декомпиляция на первый взгляд, на самом деле она реализуется довольно просто с помощью метода toString () для вызываемых функций. Проверим это на очередном примере кода, приведенном в листинге.
В приведенном выше примере кода сначала создается функция test, а затем утверждается, что метод toString () этой функции возвращает ее исходный текст. Следует, однако, иметь в виду, что значение, возвращаемое методом toStringO. будет содержать все пробелы из исходного объявления функции, въиочая и ограничители строк. Для целей тестирования в листинге использовано простое определение функции в одной строке. Если же сделать копию файла с рассматриваемым здесь кодом и внести изменения в форматирование объявления функции, то тест не пройдет до тех пор, пока проверяемая символьная строка не будет точно согласована с форматом объявления функции. Поэтому непременно учитывайте пробелы и форматирование тела функции, выполняя ее декомпиляцию.
Такому способу декомпиляции можно найти целый ряд применений, особенно при переписывании макрокоманд и кода. Но чаще всего она применяется для считывания аргументов декомпилированной функции в массив именованных аргументов, как это делается, например, в библиотеке Prototype для JavaScript. С помощью декомпиляции можно зачастую проанализировать содержимое функции и определить, какие именно значения предполагается в ней получить. В листинге приведен пример упрощенного кода из библиотеки Prototype для выведения имен параметров функции.
Функция в приведенном выше коде состоит всего лишь из нескольких строк кода, но в операторах ее тела используется немало расширенных языковых cpeACTBjavaScript. Сначала в данной функции осуществляется декомпиляция передаваемой ей функции, а для извлечения списка разделяемых запятой аргументов составляется регулярное выражение. Следует иметь в виду, что в методе ехес () предполагается получить символьную строку, и поэтому приведение аргумента функции к строковому формату с помощью метода toString () можно было бы опустить, чтобы этот метод вызывался неявно. Но в данном примере его вызов явно включен в код ради большей ясности.
Затем результат извлечения разделяется на составляющие значения, чтобы подготовить список аргументов к разным видам проверки, в том числе и на отсутствие аргументов. И наконец, проверяется отсутствие аргументов, наличие единственного аргумента и нескольких аргументов. Соответствующие тесты выполняются так, как и предполагалось.
Обращаясь с функциями подобным образом, следует принимать во внимание то обстоятельство, что далеко не все браузеры поддерживают декомпиляцию. К числу тех браузеров, которые все-таки поддерживают декомпиляцию, относится Opera Mini. Если этот браузер относится к числу поддерживаемых в веб-приложении, данное обстоятельство следует принять во внимание в том коде, где выполняется декомпиляция функции. Как подчеркивалось ранее в этой книге и особенно будет акцентировано в последующих ее главах, для того чтобы выявить наличие поддержки конкретной функциональной возможности (в данном случае декомпиляции функций совсем), не обязательно обращаться непосредственно к браузеру. Вместо этого можно прибегнуть к имитации данной функциональной возможности, чтобы проверить, поддерживается ли она в браузере. Это можно, в частности, сделать следующим образом:
var FUNCTION_DECOMPILATION = /abc(.I\n)*xyz/.test(function(abc)(xyz;});
assert(FUNCTION_DECOMPILATION,
«Function decompilation works in this browser»);
Стоит отметить, что в контексте поднятой темы стоит вкратце изучить вопрос связанный с асинхронной async JS и отложенной загрузкой JavaScript.
И в этом случае с помощью регулярного выражения, а такие выражения, к сожалению, недостаточно применяются в практике программирования на JavaScript, функция передается методу test (), причем метод toString () вызывается неявно, поскольку в методе test () предполагается получить символьную строку. А результат сохраняется в переменной для последующего применения или тестирования, как в данном случае.
Добавить комментарий