Изучаем Javascript перебирая косточки Backbone.js

// использование существующего или создание нового массива внутреннего использования для событий var events = this._events[name] || (this._events[name] = []); // в роли this — объект Events // или объект созданный конструктором, на котором было сделано так _.extend (Model.prototype, Events); // функция создается, принимает глобальный объект и только что созданную анонимную функцию (function (root, factory) {}(this, function (root, Backbone, _, $) {})) // и сразу выполняется // функция, которая once: function (name, callback, context) { var self = this; // сохраняет объект, на котором вызвана var once = _.once (function () { self.off (name, once); // чтобы знать, с какого объекта себя автоматически удалить при первом вызове callback.apply (this, arguments); }); once._callback = callback; // ссылка на колбэк навешивается еще и на функцию обертку, чтобы можно было найти и выключить событие зная колбэк return this.on (name, once, context); // функция-обертка назначается колбэком на событие }, trigger: function (name) { var args = slice.call (arguments, 1); // сохраняем аргументы без имени if (events) triggerEvents (events, args); // колбэкам, которые закреплены за своим именем, имя не передается if (allEvents) triggerEvents (allEvents, arguments); // колбэкам, которые вызываются при любом имени, передается комплект аргументов вместе с именем return this; } //, а тут пришлось малость пожертвовать красотой кода ради скорости var triggerEvents = function (events, args) { var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; switch (args.length) { case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; // внутри колбэка this будет ev.ctx case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; // самый медленный вариант, аргсы высыпятся из массива так: ev.ctx.callback(args[0], args[1], args[2] и т.д.) default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return; } }; // функция, которая вызовется на новеньком объекте ,созданном конструктором из прототипа, вместе с аргументами конструктора this.initialize.apply(this, arguments); has: function(attr) { // одна функция объекта return this.get(attr) != null; // вызывает другую функцию этого же объекта } // проверка, выполнение своей функции объектом, выбор и возврат значения if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; fetch: function(options) { options = options ? _.clone(options) : {}; // свои новая копия опций в этом пространстве имен if (options.parse === void 0) options.parse = true; // если нет парса - добавить и включить var model = this; // сохраняем объект в переменную, чтобы ссылка не менялась var success = options.success; // сохраняем старую функцию options.success = function(resp) { // подменяем новой, которая уедет в далекие дали для асинхронного общения, но будет видеть то, что посохраняли if (!model.set(model.parse(resp, options), options)) return false; if (success) success(model, resp, options); // вызов старой, если та была model.trigger('sync', model, resp, options); }; wrapError(this, options); // error из опций будет знать, с какой моделью работает return this.sync('read', this, options); // отправка функции в далекие дали для общения с по аяксу }, // клонирование модели return new this.constructor(this.attributes); // массовое добавление методов var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit']; _.each(modelMethods, function(method) { Model.prototype[method] = function() { // в прототип конструктора модели var args = slice.call(arguments); // которые передадут свои аргументы args.unshift(this.attributes); // c внутренним объектом модели воглаве return _[method].apply(_, args); // для обработки соответствующим методам Underscore }; }); attrs instanceof Model // сконструирован ли объект данным конструктором // выбор и сразу вызов необходимой функции this[first ? 'find' : 'filter'](function(model) { for (var key in attrs) { if (attrs[key] !== model.get(key)) return false; } return true; }); this.models.sort(_.bind(this.comparator, this)/*вернет функцию обертку, внутри которой всегда будет делаться типа так comparator.call(this)*/);

© Habrahabr.ru