Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Как вы пишите свои библиотеки? (https://javascript.ru/forum/misc/45940-kak-vy-pishite-svoi-biblioteki.html)

Hapson 21.03.2014 19:51

Как вы пишите свои библиотеки?
 
Наверное каждый когда-либо писал свою библиотеку всяких нужных и не очень функций. Я изучаю js, поэтому тоже вот потихоньку пишу всякие плюшки и чета их стало много. Решил оформить все в виде библиотеки, чтобы не захламлять глобальное пространство. Выглядит это так:
var GLIB = (function(){
var $G = {};

$G.scroll = function(){
	/*****/
};

$G.serialize = function(){
	/*****/
};

// и т.д. и т.п...

return $G;
}());


Однако теперь столкнулся с проблемой захламления пространства самой библиотеки.
Ну к примеру написал я некий модуль, который делает ajax запросы. У него есть настройки по дефолту, функция установки настроек, непосредственно функция отправки запросов и т.д... То есть модуль состоит из нескольких функций:

var GLIB = (function(){
var $G = {};

/*** Ajax ***/

$G.ajax = function(){/* делает запросы и выполняет заданные функции */};

$G.ajaxSetup = function(){/* установка глобальных опций */};

$G.ajaxSetting = {/* дефолтные настройки */};

/*** Other ***/

$G.scroll = function(){/*****/};

$G.serialize = function(){/*****/};

// и т.д. и т.п...

return $G;
}());


Проблема в том, что в составе модуля не все функции должны быть расшарены наружу. Например объект $G.setting не должен быть доступен для прямой записи в него. Значит что? значит нужно
// вместо
$G.ajaxSetting = {};
//сделать
var ajaxSetting = {};

Все, наружу эта переменная не доступна, но она теперь захламляет пространство внутри библиотеки...
Короче я уже не знаю, как лучше оформить свою библиотеку, чтобы и имена переменных были короткие, и чтобы потом не было конфликтов внутри.

Hapson 21.03.2014 20:01

PS да и к тому же навеное в своей библиотеке нужно отделить функции-одиночки от модулей, которые могут использовать эти самые функции-одиночки, чтобы потом можно было безболезненно выкидывать лишние модули

Aetae 21.03.2014 20:25

Ну, например, можно продолжать развивать в том же духе:) :
var GLIB = (function(){
var $G = {};
 
/*** Ajax ***/
 
$G.ajax =  (function(){
    var ajaxSetting = {/* дефолтные настройки */};
    var ajax = function(){/* делает запросы и выполняет заданные функции */};
    ajax.setup = function(){/* установка глобальных опций */};
    return ajax 
}());
 
/*** Other ***/
 
$G.scroll = function(){/*****/};
 
$G.serialize = function(){/*****/};
 
// и т.д. и т.п...
 
return $G;
}());

Sweet 21.03.2014 20:47

Hapson, если есть модули и зависимости между ними, стоит прочитать, например, эту статью.

Hapson 21.03.2014 20:59

Sweet,
Сейчас почитаю.
Немного не так, зависимостей между модулями нет.
Есть ряд функций, входящих в состав библиотеки, которые абсолютно независимы. То есть примитивные функции - поиск значения или ключа в массиве/объекте, применение функции ко всем значениям массива, trim и подобные.
А есть модули, которые мало того что состоят из нескольких функций, так они еще используют примитивные функции библиотеки.
То есть библиотека делится на две части: обязательные функции и модули. Обязательные выкидывать нельзя, модули можно

Hapson 21.03.2014 21:01

Aetae,
Ну да, что-то я об этом не подумал. Библиотека в библиотеке. Типа так:
var GLIB = (function(){
var $G = {};

/*** Ajax ***/

$G.ajax = (function(){
	
	var __setup = function(set){
		set = typeof set == "object" ? set : {};
		this.type = set.type || "GET";
		this.url = set.url || window.location.href;
		this.param = set.param || null;
		this.async = typeof set.async == "undefined" ? true : set.async === false ? false : true;
		this.contentType = set.contentType || "application/x-www-form-urlencoded";
		this.timeout = set.timeout || 3000;
		this.error = set.error || function(){};
		this.success = set.success || function(){};
		this.beforeSend = set.beforeSend || function(){};
		this.afterSend = set.afterSend || function(){};
	};
	
	var setting = new __setup();
	
	var ajax = function(set){
		var xhr = $G.getXhr();
		if(typeof set !== "object"){return xhr;}
		
	};
	
	ajax.setup = function(set){
		setting = new __setup(set);
	};
	
	ajax.getSetting = function(){return setting;};
	
	return ajax;

}());

/*** Other ***/

$G.scroll = function(){/*****/};

$G.serialize = function(){/*****/};

// и т.д. и т.п...

return $G;
}());


Только вот непонятно. Вот в примере есть внутренние переменные: __setup и setting. Если они используются в других функциях, то они получается остаются жить после завершения работы функции обертки?

Aetae 21.03.2014 21:47

Ну да. В этом вся суть замыкания. Я думал раз уж вы его используете для своей библиотеки, то понимаете что это такое...

Maxmaxmaximus12 21.03.2014 22:15

Если твоя библиотека делится на модули, и они зависимы друг от друга, то ты можешь использовать паттерн "иньекция зависимости", вот держи братишка, я тебе иньектор принес:


var module = new function () {

    var modules = {};


    function inject(factory) {

        var require = factory.toString()
                .match(/\(([\s\S]*?)\)/)[1]
                .match(/[\$\w]+/img) || [];

        return factory.apply(null, require.map(module));

    }


    function module(name, factory) {

        if (!factory) {
            var module = modules[name];
            return module.instance || (module.instance = inject(module.factory));
        }

        modules[name] = {
            factory : factory,
            instance: null
        };

    }


    return module;

};



работает функция module так
// описываем модуль
module('http', function () {

    return {
        ololo: function () {
            alert('ololo!')
        }
    }

});


// обращаемся к модулю
var http = module('http');
http.ololo() // ololo!


вторым аргументом передается функция "фабрика", тот обьект который она вертет он и будет модулем, и он будет возвращаться при module('http'). Все модули создаются только один раз, так что module('http') === module('http').


Если какой-то модуль зависит от другого модуля то мы можем в коде одного модуля обратиться к другому:

module('http', function () {

    return {

    }

});


module('ajax', function () {

    // обратились из одного модуля к другому
    var http = module('http');

    return {

    }

});



но лучше просто написать ИМЯ необходимого модуля в параметрах к функции фабрике) тогда туда ПО ИМЕНИ необходимй модуль и передастся.

module('http', function () {

    return {

    }

});


module('ajax', function (http) {

    http  //модуль автоматически подключился по имени аргумента 

    return {

    }

});





Ну или если тебе не нужны всякие модули, иньекции, то используй просто такой шаблон:


var myLibrary = new function () {

    function trim() {

    }

    function find() {

    }

    // функция которая не будет доступна извне, она является внутренней для библиотеки
    function select() {

    }


    // функции которые хотим сделать доступными пользователю
    return {
        trim: trim,
        find: find
    }

};

Hapson 21.03.2014 23:28

Aetae,
Читал я про замыкания... много раз читал. Ну вроде как начал понимать, как это работает.
Maxmaxmaximus12,
Спасибо :)
Интересный подход.

Maxmaxmaximus12 22.03.2014 00:59

Hapson, или к примеру, одна функция использует несколько служебных, тогда описывай так



var myLibrary = new function () {


    // утилитарная функция, которая может быть доступна всем функциям фреймворка
    // тут вверху помещай более общие функции, выполняющие рутиную работу.
    // начинается с одного подчеркивания, как символ того что она вспомогательная.
    function _getElement() {

    }



    // публичная функция
    this.trim = new function () {

        // служебная функция которая видна только функции trim
        function find() {

        }

        return function () {
            // код функции trim
        }
    };



    // публичная функция
    this.ajax = new function () {

        // служебная переменная, которая видна только функции ajax
        var ajaxPort = 80;

        // служебная функция которая видна только функции ajax
        function ajaxSettings() {

        }

        return function () {
            // код функции ajax
        }
    };


};


а вообще лучше разбивать код на модули и пихать их в разные файлы, а потом делать сборку проекта в один файл с помощью прогарммы gulp


Часовой пояс GMT +3, время: 01:47.