Решил повысить свои уровень и разобраться, как пишут код крутые мальчики и девочки. Для этого взял кусочек из Бутстрапа (его же крутые мальчики и девочки пишут
) и попытался разобраться.
Выкладываю урезанный фрагмент со своими комментариями. Ответьте пожалуйста, на вопросы /* ? */ до которых не догнал.
Возможно кто-то объяснит смысл построения кода именно таким образом или подскажет лучший способ.
$('#example').tooltip(options) // Создаем объект tooltip для объекта с id="example". И начинается самое интересное. Ниже фрагмент из Бутстраповского плагина, вызывающего всплывающие подсказки
!function ($) { /*? !function ($) {}(window.jQuery); что за конструкция ?*/
"use strict"; // jshint ;_; — это не мой комментарий. Что они хотели этим сказать?
// Strict Mode накладывает слой ограничений на JavaScript, он отгораживает вас от опасных частей языка (те части, которые есть исторически, но лучше чтобы их не было) и позволяет снизить вероятность ошибки.
// А еще Strict Mode не оборачивает функцию в объект, из-за чего выполнение происходит быстрее
/*? Strict Mode распространяется на объекты созданные в функции? Если да, то результат выполнения методов на строках ["".metod()] тоже будет оптимизироваться ?*/
/* TOOLTIP PUBLIC CLASS DEFINITION
* =============================== */
var Tooltip = function (element, options) { /*? зачем передавать в конструктор параметр element если он передается из цепочки jQuery [$('#example')] ?*/
this.init('tooltip', element, options)
}
Tooltip.prototype = {
constructor: Tooltip // переопределяем стандартное свойство constructor. Иначе затрется /*? нужно ли это? может проще всегда создавать через new ?*/
, init: function (type, element, options) {
this.type = type
this.$element = $(element) /*? начинать переменные, в которых объекты jQuery, с $ хороший стиль ?*/
this.options = this.getOptions(options) /*? теперь в нашем объекте и defaults и options. Может лучше defaults перезаписать значениями из options ?*/
this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) /*? 'click.' + this.type = 'click.tooltip' Это что такое ?*/
/*? Как-то через proxy не очень красиво. Может лучше что-то вроде этого $.bind("click", function(e) {this = e.target}) ?*/
}
, getOptions: function (options) {
options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
// Тут мы ищем наш метод [tooltip] в объекте jQuery и передаем из него дефолтные параметры, попутно обновляя их парметрами из options и this.$element.data()
// {} отвечает за то, чтобы дефолтные параметры не изменились в прототипе + чтобы были заменены только те, что есть в options и т.п.
// В итоге в переменной options у нас все неуказанные параметры равны дефолтным
if (options.delay && typeof options.delay == 'number') { /*? Проверка №1 Зачем проверять options.delay? Зачем, вообще, обе проверки, если потом еще одна будет ?*/
options.delay = {
show: options.delay
, hide: options.delay
}
}
return options
}
, enter: function (e) {
var self = $(e.currentTarget)[this.type](this._options).data(this.type) /*? _options, зачем называть с подчеркивания ?*/
if (!self.options.delay || !self.options.delay.show) return self.show() /*? Проверка №2. Зачем проверять self.options.delay ?*/
}
, toggle: function () { /*? Опять же, не проще делать toggle: function (this) ?*/
this[this.tip().hasClass('in') ? 'hide' : 'show']()
}
, destroy: function () {
this.hide().$element.off('.' + this.type).removeData(this.type)
}
}
/* TOOLTIP PLUGIN DEFINITION
* ========================= */
$.fn.tooltip = function ( option ) { /*? Самый непонятный блок ?*/
return this.each(function () {
var $this = $(this)
, data = $this.data('tooltip')
, options = typeof option == 'object' && option /*? Зачем столько проверок? Без них что-то развалиться ?*/
if (!data) $this.data('tooltip', (data = new Tooltip(this, options))) /* ? Тут же сделали через new и зачем нужны были все эти Constructor ?*/
if (typeof option == 'string') data[option]() /* ? хм... ? */
})
}
$.fn.tooltip.Constructor = Tooltip /*? Заменяем стандартный конструктор на наш. Зачем ?*/
$.fn.tooltip.defaults = {
selector: false
, delay: 0
}
}(window.jQuery);