Backbone. js source code analysis: extend, Backbone. View

Source: Internet
Author: User
Backbone version: 0.9.2

 

1. parse Backbone. Model (Collection | Router | View). extend

 

(1). Find the extend Definition

// Define the extend Function
Var extend = function (protoProps, classProps ){
/*
Usually we use Backbone. XXX. extend method to create a Model, View and other object types, so here this represents Backbone. model, Backbone. view and other Constructor (Note: The similar descriptions below are unified with Backbone. view is an example)
*/
Var child = inherits (this, protoProps, classProps );
Child. extend = this. extend;
Return child;
};
// Set the extend method of Model, Collection, Router, and View to extend
Model. extend = Collection. extend = Router. extend = View. extend = extend;

(2) analyze the inherits function source code

Var ctor = function (){};
Var inherits = function (parent, protoProps, staticProps ){
Var child;
// Determine whether protoProps is a prototype object. If yes, assign the child value to the constructor to which the prototype object belongs.
If (protoProps & protoProps. hasOwnProperty ('constructor ')){
Child = protoProps. constructor;
} Else {
// Otherwise, assign a new constructor to child.
Child = function (){
// The inherits function returns a constructor. We use new child () to call this Constructor (for example, AppView = Backbone. view. extend ({}); var appView = new AppView ();), so here this points to our new instance (for example, var appView = new AppView (), then this points to appView)
// The new AppView operation is actually Backbone. Model. apply (this, arguments). That is to say, when we instantiate the appView, we actually call Backbone. Model.
Parent. apply (this, arguments );
};
}

// Here, parent is the this in 1, that is, Backbone. view, _ extend is underscore. A function in js sets all attributes and attribute values of all parameters after the second and second parameters to the first parameter (the specific implementation of _ extend is not described here, see underscore. js source code)
_. Extend (child, parent );

// Ctor is a constructor with empty content. Set the prototype object to Backbone. View. prototype.
Ctor. prototype = parent. prototype;
// Set the child prototype object to an instance of the ctor, and the child. prototype. contructor points to the ctor
Child. prototype = new ctor ();
// Copy all attributes of the second parameter Backbone. View. extend (usually an object) to child. prototype.
If (protoProps) _. extend (child. prototype, protoProps );

// Copy all attributes of the third parameter Backbone. View. extend (usually an object) to child, that is, set static attributes or methods for child.
If (staticProps) _. extend (child, staticProps );

// After the child. prototype = new ctor is executed, the child. prototype. constructor does not point to the child, so the settings must be displayed here.
Child. prototype. constructor = child;

// The _ super _ attribute is not defined in EcmaScript. This attribute is the super class corresponding to the backbone record child.
Child. _ super _ = parent. prototype;

Return child;
};

(3) summarize the prototype object chain

New Custom View () class --> child (user-created constructor) prototype object --> an instance of ctor (some of our custom functions and methods are set on this instance) prototype object --> Backbon. view. prototype

 

 

 

2. parse Backbone. View
Example:

AppView = Backbone. View. extend ({});
Var appView = new AppView ({});

(1) Check the source code of Backbone. View first:

Var viewOptions = ['model', 'collect', 'El', 'id', 'tes buckets', 'classname', 'tagname'];
Var View = Backbone. View = function (options ){
//_. UniqueId is also underscore. A function in js stores an integer variable through a closure. Each time you call this function, the integer variable increases by 1, connect the integer variable to a string with the passed prefix (view prefix), and return the string
This. cid = _. uniqueId ('view ');
// Call Backbone. view. prototype. _ configure is used to merge options and AppView. prototype. options, and set the attribute with the specified attribute name and value different from false to this (_ configure is described later)
This. _ configure (options || {});
// Perform some operations based on whether this. el is assigned a value.
This. _ ensureElement ();
// Call Backbone. View. prototype. initialize as this method. By default, Backbone. View. prototype. initialize is a function with empty content. In general, we will define an initialize function in options (in AppView = Backbone. view. extend ({initialize :...}) it is defined here as AppView. prototype. initialize) to override Backbone. view. prototype. initialize
This. initialize. apply (this, arguments );
This. delegateEvents ();
};

(2) The _ configure function is simplified as follows:

_. Extend (View. prototype ,{
_ Configure: function (options ){
// This indicates an instance of our custom View, that is, appView.

// Determine whether this has the options attribute. If yes, set this. the options and options are merged and assigned to options. By parsing the prototype object chain obtained by the extend method, we can find that this is not instantiated yet and Backbon. view. prototype does not have this attribute, so this. options can only be from AppView. prototype (an instance of ctor), that is, this. options is in Backbone. view. extend ({options :...}) and options is the first parameter of the AppView constructor.
If (this. options) options = _. extend ({}, this. options, options );
// Traverse viewOptions. If options [viewOptions [I] has a value, assign it to this
For (var I = 0, l = viewOptions. length; I <l; I ++ ){
Var attr = viewOptions [I];
If (options [attr]) this [attr] = options [attr];
}
This. options = options;
}
});

(3) delegateEvents code parsing

// A regular expression that matches strings that are not separated by spaces or line breaks, or strings that are separated by spaces or line breaks.
Var delegateEventSplitter =/^ (\ S +) \ s * (. *) $ /;
DelegateEvents: function (events ){
// Determine whether the events attribute (an object can be used or a function of the returned object) exists. If it does not exist
If (! (Events | (events = getValue (this, 'events') return;
// Remove the events bound to this. $ el.
This. undelegateEvents ();
// Traverse all specified events
For (var key in events ){
// Events [key] is either a function or a method name of the View.
Var method = events [key];
If (! _. IsFunction (method) method = this [events [key];
// If the function for the event is not found, the system will throw and remove the function.
If (! Method) throw new Error ('method "'+ events [key] +'" does not exist ');
// Cut the event name. For example, "click. toggle" will be cut to match = ['click. toggle ', 'click','. toggle ']
Var match = key. match (delegateEventSplitter );
// Set the event name and Selector
Var eventName = match [1], selector = match [2];
// _. Bind is the underscore. js method. Call this method here to obtain a function method. this inside the function references an instance of our custom View, that is, appView.
Method = _. bind (method, this );
// Add a namespace for the event so that all different types of events can be removed at one time through the namespace
EventName + = '. delegateEvents' + this. cid;
// Use jQuery to bind events.
// If the selector is a Null String, bind the event to $ el.
If (selector = ''){
This. $ el. bind (eventName, method );
} Else {
// Bind events to the sublevel of this. $ el according to the selector
This. $ el. delegate (selector, eventName, method );
}
}
}
// Attaches the undelegateEvents source code.
UndelegateEvents: function (){
// Remove the currently passed this. $ el. bind or this. $ el. delegate bound and namespace is '. delegateEvents '+ this. all cid events (removed by namespace)
This. $ el. unbind ('. delegateEvents' + this. cid );
}

// Add the source code of getValue.
Var getValue = function (object, prop ){
If (! (Object & object [prop]) return null;
Return _. isFunction (object [prop])? Object [prop] (): object [prop];
};

(4) _. bind source code parsing, the code is simplified as follows:

FuncProto = Function. prototype;
NativeBind = FuncProto. bind;
Var ArrayProto = Array. prototype;
Var slice = ArrayProto. slice;
Var ctor = function (){};
_. Bind = function bind (func, context ){
Var bound, args;
// Determine whether the current browser has implemented Function. prototype. bind of EcmaScript 5.1. If yes, call this method directly and return a Function
// If returned here, the list of returned function parameters is: (arguments [2], arguments [3],...), and this in the function references context.
If (func. bind === nativeBind & nativeBind) return nativeBind. apply (func, slice. call (arguments, 1 ));
// If func is not a function, return
If (! _. IsFunction (func) throw new TypeError;
// Obtain the third and all parameters following the context (that is, all parameters after the context)
Args = slice. call (arguments, 2 );
Return bound = function (){
// If bound is not used as the constructor, a function is returned here.
If (! (This instanceof bound ))
{
// If it is returned here, the list of returned function parameters is: (args [0], args [1],..., arguments [0], arguments [1],...), this in the function references the context
// Note that args is a section of arguments when calling the outer _. bind function (implemented using the closure). arguments is the parameter object referenced when calling the function returned here.
Return func. apply (context, args. concat (slice. call (arguments )));
}
// Ctor is a constructor with empty content. set its prototype to func. prototype.
Ctor. prototype = func. prototype;
// Instantiate a ctor object
Var self = new ctor;
// After the above two statements are executed, a scope chain is constructed: Class of self --> ctor prototype object --> func. prototype

// Call the func function to obtain a returned object. The list of returned function parameters is: (args [0], args [1],..., arguments [0], arguments [1],...), this in the function references self.
// Note that args is a section of arguments when calling the outer _. bind function (implemented using the closure). arguments is the parameter object referenced when calling the function returned here.
Var result = func. apply (self, args. concat (slice. call (arguments )));

// The following code returns an object. Note: if an object is returned in the constructor, the object referenced by this in the constructor will be discarded.

// If the result is of the reference type (such as Object or Array), the result is returned.
If (Object (result) = result)
{
Return result;
}
// Otherwise, self is returned.
Return self;
};
};

 

(5) Function. prototype. bind method of EcmaScript 5.1

Function. prototype. bind (thisArg [, arg1 [, arg2,…])

Function. prototype. bind returns a new Function object. this of this Function object is bound to the thisArg parameter. Essentially, this allows you to execute a function in other object chains. Example: function locate (){
Console. log (this. location );
}
Function Maru (location ){
This. location = location;
}
Var kitty = new Maru ("cardboard box ");
Var locateMaru = locate. bind (kitty );
LocateMaru ();

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.