На самом деле это довольно простая и забавная задача написать такие скрипты.
Вот большой пример того, как превратить обычную функцию в нечто вроде этого:
Я хотел бы начать с воображаемым сценарием. Я включил scriptLoader, который загружает файл яваскрипт асинхронно:
window.loadScript = function(src){
const scriptTag = document.createElement('script');
scriptTag.async = true;
scriptTag.src = src;
const anyOtherScriptTag = document.getElementsByTagName('script')[0];
anyOtherScriptTag.parentNode.insertBefore(scriptTag, anyOtherScriptTag);
}
Когда названные так: loadScript("/url.js")
будет вставить новый тег сценария (до первого тега сценария) в DOM и браузер загрузит скрипт ,
Пока все хорошо. Предположим, я хочу передать аргументы этого скрипта до его загрузки. Внутри скрипта, который будет загружен, я получаю доступ к уникальному глобальному объекту. Назовем это window.myScriptArgs
. Поэтому в идеале после загрузки скрипта он считывает window.myScriptArgs и выполняет соответственно.
Теперь я мог бы сделать window.myScriptArgs = []
и назвать его в день, но так как мой гипотетический пример будет только загрузить файл с одного сценария, я добавить логику к функции loadScript, а также.
window.loadScript = function(src){
window.myScriptArgs = window.myScriptArgs || [];
const scriptTag = document.createElement('script');
scriptTag.async = true;
scriptTag.src = src;
const anyOtherScriptTag = document.getElementsByTagName('script')[0];
anyOtherScriptTag.parentNode.insertBefore(scriptTag, anyOtherScriptTag);
}
loadScript("/my-script.js");
Хорошо, так что я могу проверить, если myScriptArgs уже присутствует, и если я не поставил его в пустой массив. Теперь я также знаю, что my-script.js
раскрывает глобальный метод myScript(). Поэтому я пишу для этого заглушку. Эта заглушка поместит все аргументы, полученные к нему в массив myScriptArgs:
window.myScript =() => {
window.myScriptArgs = window.myScriptArgs || [];
window.myScriptArgs.push(arguments);
}
Теперь я могу позвонить loadScript и немедленно вызвать MyScript() с заданными аргументами. Не нужно беспокоиться о проблемах с загрузкой или о многом. После загрузки «my-script.js» он считывает window.myScriptArgs
и действует как исключение. Код выглядит так:
window.myScript =() => {
window.myScriptArgs = window.myScriptArgs || [];
window.myScriptArgs.push(arguments);
}
window.loadScript = function(src){
window.myScriptArgs = window.myScriptArgs || [];
const scriptTag = document.createElement('script');
scriptTag.async = true;
scriptTag.src = src;
const anyOtherScriptTag = document.getElementsByTagName('script')[0];
anyOtherScriptTag.parentNode.insertBefore(scriptTag, anyOtherScriptTag);
}
loadScript("/my-script.js");
myScript('command', 'args', 'args1');
myScript('command2', 'args3', 'args4');
Хорошо, работает нормально.Давайте его оптимизировать. Сначала я объединить loadScript
и myScript
окурок к одной функции, называемой initMyScript():
window.initMyScript = function(src){
window.myScriptArgs = window.myScriptArgs || [];
window.myScript = window.myScript || function(){
window.myScriptArgs.push(arguments);
}
const scriptTag = document.createElement('script');
scriptTag.async = true;
scriptTag.src = src;
const anyOtherScriptTag = document.getElementsByTagName('script')[0];
anyOtherScriptTag.parentNode.insertBefore(scriptTag, anyOtherScriptTag);
}
initMyScript("/my-script.js");
myScript('command', 'args', 'args1');
myScript('command2', 'args3', 'args4');
Это ничего слишком фантазии атм. Теперь я собираюсь избавиться от многочисленных вызовов window.
, передав window
в качестве аргумента initMyScript
. Я также сделаю это с document
.
Сценарий выглядит следующим образом:
window.initMyScript = function(p, a, src){
p.myScriptArgs = p.myScriptArgs || [];
p.myScript = p.myScript || function(){
p.myScriptArgs.push(arguments);
}
const scriptTag = a.createElement('script');
scriptTag.async = true;
scriptTag.src = src;
const anyOtherScriptTag = a.getElementsByTagName('script')[0];
anyOtherScriptTag.parentNode.insertBefore(scriptTag, anyOtherScriptTag);
}
initMyScript(window, document, "/my-script.js");
Теперь давайте посмотрим, где я повторяю себе, чтобы спасти еще несколько битов. Я использую строку script
дважды, то же самое для myScript
:
window.initMyScript = function(p, a, s, c, src){
p.myScriptArgs = p.myScriptArgs || [];
p[c] = p[c] || function(){
p.myScriptArgs.push(arguments);
}
const scriptTag = a.createElement(s);
scriptTag.async = true;
scriptTag.src = src;
const anyOtherScriptTag = a.getElementsByTagName(s)[0];
anyOtherScriptTag.parentNode.insertBefore(scriptTag, anyOtherScriptTag);
}
initMyScript(window, document, 'script', 'myScript', "/my-script.js");
Следующий шаг в моем пути, чтобы сделать переменные коротка. И я также включить эту функцию в прямоприменяемых функцию, чтобы сохранить window.initMyScript
определения:
(function(p, a, s, c, src){
p.myScriptArgs = p.myScriptArgs || [];
p[c] = p[c] || function(){
p.myScriptArgs.push(arguments);
}
const q = a.createElement(s);
q.async = true;
q.src = src;
const d = a.getElementsByTagName(s)[0];
d.parentNode.insertBefore(q, d);
})(window, document, 'script', 'myScript', "/my-script.js");
И к моей последней тайне: я редактировать параметры функции, чтобы запутать человек, а также Минимизировать код еще больше. Вы действительно можете связать функции в javascript с помощью запятых;).
(function(p, a, s, c, A, l, i){
p["myScriptArgs"]=p["myScriptArgs"]||[],p[c] = p[c]||function(){
p["myScriptArgs"].push(arguments)},
l = a.createElement(s);l.async = true;l[A] = A;
i = a.getElementsByTagName(s)[0];
i.parentNode.insertBefore(l, i);
})(window, document, 'script', 'myScript', "/my-script.js");
myScript("arg1", "arg2");
myScript("arg2", "arg3");
Обратите внимание, что я добавить два дополнительных параметра в функции, то это потому, что мне нужно, чтобы сохранить элемент, возвращаемый createElement
и не хотите использовать var
заявление;).
Вы можете принять это еще дальше, но вы понимаете. Для небольших функций вы можете сделать это самостоятельно без проблем.
Кроме того, вы можете использовать Minifier как UglifyJS, а затем переименовать переменные себя после этого, если вы действительно в этом всю изограмме вещи ...
Примечание: Я не испытывал какие-либо из этого кода. Здесь будут драконы. Мнимый код - моя неудачная попытка де-обфускации примера Google. Фрагмент google-analytics работает почти так же, как и мой пользовательский фрагмент. GA оптимизирует немного больше (например, превращая true в 1), но вы получите точку.
Узнайте больше о вещах, используемых в моем примере: Immediately Invoked Function Expression Property accessors (especially Bracket notation)
И JavaScript конкретных вещей, как проходит три аргумента в функцию, которая принимает 5.
Я не знаю, но это такой крошечный скрипт, его можно легко выполнить вручную, используя желаемые имена параметров функции. –
... Интересно, что скрипт 'ga' использует скобку с строковым литералом:' i ['GoogleAnalyticsObject'] ', какие миниторы (включая Closure Compiler) обычно преобразуют в синтаксис точек, поэтому это заставляет меня думать, что это вероятно, выполняется вручную, при этом скобки используются только в том случае, если он выполняется через CC, поэтому он не превращает его в 'window.b =" ga "'. –
@squint Спасибо! Да, похоже, что это было сделано вручную, было просто интересно, не пропал ли я что-то. – lmenus