1 _.extend = function(obj) { 2 // each循環參數中的一個或多個對象 3 each(slice.call(arguments, 1), function(source) { 4 // 將對象中的所有屬性複製或覆蓋到obj對象 5 for(var prop in source) { 6 obj[prop] = source[prop]; 7 } 8 }); 9 return obj; 10 };
1:上面是underscore舊版本的extend方法代碼(和如今API調用方法不一樣),經我測試object.slice沒法使用,可是加入下面兩行就能夠slice.call(x,y)這樣調用了,可是依舊不能夠object.slice(undefined)。css
1 var ArrayProto = Array.prototype; 2 var slice = ArrayProto.slice;
2:現版本的extend方法html
1 // Retrieve all the property names of an object. 2 _.allKeys = function(obj) { 3 if (!_.isObject(obj)) return []; 4 var keys = []; 5 for (var key in obj) keys.push(key); 6 // Ahem, IE < 9. 7 if (hasEnumBug) collectNonEnumProps(obj, keys); 8 return keys; 9 }; 10 11 _.extend = createAssigner(_.allKeys); 12 13 var createAssigner = function(keysFunc, undefinedOnly) { 14 return function(obj) { 15 var length = arguments.length; 16 if (length < 2 || obj == null) return obj; 17 for (var index = 1; index < length; index++) { 18 var source = arguments[index], 19 keys = keysFunc(source), 20 l = keys.length; 21 for (var i = 0; i < l; i++) { 22 var key = keys[i]; 23 if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; 24 } 25 } 26 return obj; 27 }; 28 };
3:JS精確整數最大值和判斷應該以數組仍是對象的方式進行迭代jquery
1 var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; 2 var isArrayLike = function(collection) { 3 var length = collection != null && collection.length; 4 return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; 5 };
1:模塊化開發,AMD數組
2:從backbone的整體結構來看,是一個當即執行的函數表達式,參數是一個匿名函數。(function(){})()和(function(){}())的目的是將函數聲明轉換爲函數表達式,消除Js引擎在識別函數聲明和函數表達式上的歧義,除了小括號外還有其餘運算符可以作到,詳細介紹能夠參照這篇文章:js中(function(){…})()當即執行函數寫法理解瀏覽器
1 (function(factory) { 2 //模塊定義 3 })(function(root, Backbone, _, $) { 4 //Backbone 5 });
模塊處理內容以下:app
1 function(factory) { 2 3 // Establish the root object, `window` (`self`) in the browser, or `global` on the server. 4 // We use `self` instead of `window` for `WebWorker` support. 5 //拿到當前環境中的全局對象;瀏覽器中爲window,self也是瀏覽器提供的一個全局對象,始終指向window 6 //server端的運行環境則提供global這個全局對象 7 var root = (typeof self == 'object' && self.self === self && self) || 8 (typeof global == 'object' && global.global === global && global); 9 10 // Set up Backbone appropriately for the environment. Start with AMD. 11 //若是有amd加載器則將Backbone定義包裝成amd加載器可識別的模塊 12 if (typeof define === 'function' && define.amd) { 13 //AMD規範定義兩個全局函數define和requrie,而且規定define有個amd屬性,來區分amd的define和普通名爲define的函數 14 define(['underscore', 'jquery', 'exports'], function(_, $, exports) { 15 // Export global even in AMD case in case this script is loaded with 16 // others that may still expect a global Backbone. 17 root.Backbone = factory(root, exports, _, $); 18 }); 19 20 // Next for Node.js or CommonJS. jQuery may not be needed as a module. 21 //若是運行在Node端,則將Backbone包裝成CommonJs的模塊 22 } else if (typeof exports !== 'undefined') { 23 var _ = require('underscore'), $; 24 try { $ = require('jquery'); } catch (e) {} 25 factory(root, exports, _, $); 26 27 // Finally, as a browser global. 28 //以上兩種狀況都沒有,則以最簡單的執行函數方式,將函數的返回值做爲全局對象Backbone 29 } else { 30 root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$)); 31 } 32 33 }
factory部分總體結構以下:模塊化
1 function(root, Backbone, _, $) { 2 // Backbone.Events 3 // --------------- 4 5 // Backbone.Model 6 // -------------- 7 8 // Backbone.Collection 9 // ------------------- 10 11 // Backbone.View 12 // ------------- 13 14 // Backbone.Router 15 // --------------- 16 17 // Backbone.History 18 // ---------------- 19 20 // Helpers 21 // ------- 22 }
Backbone的每一個部分都有本身的extend屬性,而且都有默認繼承的方法,參數只是對默認方法的覆蓋函數
1 // Helper function to correctly set up the prototype chain for subclasses. 2 // Similar to `goog.inherits`, but uses a hash of prototype properties and 3 // class properties to be extended. 4 //protoProps放置到子類原型上的屬性 5 //staticProps模擬靜態屬性,直接放置到子類上 6 var extend = function(protoProps, staticProps) { 7 var parent = this;//利用局部變量保存this關鍵字 8 var child; 9 10 // The constructor function for the new subclass is either defined by you 11 // (the "constructor" property in your `extend` definition), or defaulted 12 // by us to simply call the parent constructor. 13 //若是protoProps中有constructor屬性,則將constructor指向的函數做爲構造函數 14 if (protoProps && _.has(protoProps, 'constructor')) { 15 child = protoProps.constructor; 16 } else {//沒有構造函數,則利用一個默認的函數做爲構造函數。 17 //基本上屬於組合式繼承 18 child = function(){ return parent.apply(this, arguments); }; 19 } 20 21 // Add static properties to the constructor function, if supplied. 22 //underscore中的方法,與常見的mixin函數相似 23 _.extend(child, parent, staticProps); 24 25 // Set the prototype chain to inherit from `parent`, without calling 26 // `parent`'s constructor function and add the prototype properties. 27 //將child的原型鏈與parent.prototype關聯。 28 //_.create函數,的做用相似Object.create,第一個參數是要被繼承的原型對象,第二個參數是要混入到新對象的鍵值對 29 child.prototype = _.create(parent.prototype, protoProps); 30 child.prototype.constructor = child;//原型中的constructor屬性指向child 31 32 // Set a convenience property in case the parent's prototype is needed 33 // later. 34 child.__super__ = parent.prototype;//設置一個私有屬性指向父類的原型 35 36 return child; 37 };
1 // Set up inheritance for the model, collection, router, view and history. 2 Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
注意:具體model的屬性是在new的時候輸入的,extend的時候只是對實例進行一些方法和屬性的設置,好比default就是當new的時候不輸入的屬性的默認值!測試
①模型重點
當模型實例化時,他的initialize方法能夠接受任意實例參數,其工做原理是backbone模型自己就是構造函數,因此可使用new生成實例:
var User = Backbone.Model.extend({ initialize: function (name) { this.set({name: name}); } }); var user = new User('刀狂劍癡'); assertEqual(user.get('name'), '刀狂劍癡');
②
constructor / initializenew Model([attributes], [options])
當建立model實例時,能夠傳入 屬性 (attributes)初始值,這些值會被 set (設置)到 model。 若是定義了 initialize 函數,該函數會在model建立後執行。
new Book({ title: "One Thousand and One Nights", author: "Scheherazade" });