- PVSM.RU - https://www.pvsm.ru -

JavaScript loader без define

Привет!

Всем известно решение задачи загрузки скриптов.
Например Curl.JS, Require.JS, + популярные frameworks умеют это тоже.

Вот и недавно была статья [1] про это от уважаемого azproduction [2].

Но все же интересно, есть ли альтернативы AJS, CJS, etc, учитывая ссылку [3].

Что если есть возможность загрузить JavaScript забыв про обыденные «мелочи» типа:

define( function(){
  return MyBeautifulObject;
});

Пример для самых нетерпеливых. [4]

Далее небольшая заметка о том как это работает.

Началось всё вот с такой бесполезной конструкции:


var fn = ( function(){
    var ffn = Function.apply( this, arguments ) ;
    var init = this;
    return ( function( ffn ){
        alert( '1: '+init )
        alert( '2: '+this )
        var zfn = function(){
            alert( '3: '+init )
            alert( '4: '+this )
            return ffn.apply( init, arguments );
        };
        return zfn;
    }).call( init, ffn );
} ).apply( 456, [ 'a', 'b', ' alert(a+b); alert( "this: " + this ); return this; ' ] );

alert( 'result: ' + fn.call( 123, 5, 5 ) );​

JS Fiddle [5]

Потом, постепенно трансформировалось в это:


var fns = ( function(){
    var fn = new Function( 'with( this ){ return ' + Function.apply( this, arguments ).toString() + '; }' );
    fn = fn.call( this );
    return function(){
        return fn.apply( this, arguments );
    };
} ).apply( { bb: 789 }, [ 'a', 'b', ' alert(a+b); alert(this); alert( "bb: " + bb ); return bb; ' ] );
    
alert( 'result: ' + fns.call( 123, 5, 5 ) );

JS Fiddle [6]

Как видно из кода, через with определяется ссылка на примесь из переданного в scope объекта: bb.

И, наконец, финальный код загрузчика скриптов в виде метода для jQuery:

(function( jQuery, undefined ){
jQuery.loadSubScript = function( url, scope, thisName, returnCallback ){
    // если не передан scope сделаем его глобальным
    var scope = scope || window;
    // аналогично
    var thisName = thisName || window;
    
    $.ajax( {
          url: url
        , type: 'GET'
        , dataType: 'text'
        , success: function( data ){
            try{
                
                // создаем полученный код, не забываем про with
                var fns = new Function( 

                         'with( this ){ return ' 
                                + Function.apply( null, [ data ] )
                                + '; }' 

                );

                // инициализируем замыкание с with
                fns = fns.call( scope );
                // инициализируем замыкание с this
                var turn = fns.call( thisName );
                // возвращаем результат в callback, если он есть
                returnCallback && returnCallback( turn );
                
            }catch(e){ alert(e); }
        }
        , error: function( jqXHR, textStatus, errorThrown ){ 
                alert('Loader Error:n' + errorThrown ); 
        }
    } );        
};
})( jQuery );

Тот же самый пример для Терпеливых. [4]

Что можно?

  • Просто загрузить скрипт в глобальный объект: window.
  • Загрузить скрипт с «подменой» scope: window + YourOwnScopObject.
  • Загрузить скрипт с подменой ему this.
  • Вернуть что-нибудь в callback, например, просто написав в вашем загружаемом скрипте return.
  • Избавиться от define().

Конечно, если что нибудь будет нести var, то оно будет внутри созданного замыкания. Без var, как и должно быть — попадет в window. То, что является методами переданного в scope объекта будет доступно без точки. С this — всё как обычно, в случае его подмены.

Пользуйтесь на здоровье!

Ссылка на GIT [7]

Можно рассказать коллеге.

Best Regards!

PS: Не знаю какую лицензию выбрать, наверное MIT + GPLv3.

Автор: wentout


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/9443

Ссылки в тексте:

[1] статья: http://habrahabr.ru/post/145269/

[2] azproduction: http://habrahabr.ru/users/azproduction/

[3] ссылку: http://tomdale.net/2012/01/amd-is-not-the-answer/

[4] Пример для самых нетерпеливых.: http://wentout.github.com/SubScriptLoader/

[5] JS Fiddle: http://jsfiddle.net/YEC3w/

[6] JS Fiddle: http://jsfiddle.net/Nh7uN/

[7] Ссылка на GIT: https://github.com/wentout/SubScriptLoader