Parsing John Resig Simple JavaScript inheritance code _javascript Tips

Source: Internet
Author: User
Tags extend serialisation

As the author of the translation will add their own understanding in order to learn and use, if the English good students can see the following, such as a translation error in the article, please leave a message. Communicate and correct. (:
======================enein translation =========================

John Resig wrote an "inheritance" of JavaScript similar to other languages, inspired by Base2 and Prototypejs. He named the article "Simple JavaScript Inheritance". He used some ingenious techniques to implement the Super method.
You can also read the original text and there will be detailed instructions, he also in his "Secrets of a JavaScript Ninja" in the introduction. There may be some differences in the method in the book, which adds the subclass method to the object rather than creating a global variable.
Original Script-john resig Simple JavaScript inheritance
Here is the pardon code, and I removed some comments using it to look clearer.

Copy Code code as follows:

(function () {
var initializing = false, Fntest =/xyz/.test (function () {xyz;})? /\b_super\b/:/.*/;
This. Class = function () {};
Class.extend = function (prop) {
var _super = This.prototype;
initializing = true;
var prototype = new This ();
initializing = false;
for (var name in prop) {
Prototype[name] = typeof Prop[name] = = "function" &&
typeof _super[name] = = "function" && fntest.test (prop[name))?
(function (name, FN) {
return function () {
var tmp = This._super;
This._super = _super[name];
var ret = fn.apply (this, arguments);
This._super = tmp;
return ret;
};
}) (name, Prop[name]):
Prop[name];
}
function Class () {
if (!initializing && this.init)
This.init.apply (this, arguments);
}
Class.prototype = prototype;
Class.constructor = Class;
Class.extend = Arguments.callee;
return Class;
};
})();

Breakdown of the Simple inheritance script
Let's analyze how it is implemented and what technologies are being used.

Copy Code code as follows:

(function () {//...}) ();

First we create a self executing anonymous function that creates a scope for the code.

Copy Code code as follows:

var initializing = False

This initializing variable means very straightforward, and it is Boolean to check when the class Function (described later) is invoked. Set initializing to True/false when creating an instance or simply return an object to the current prototype chain to achieve "inheritance".

If we create an instance (initializing = = False), exactly class has an Init method, so init will execute automatically. Or, if we just assign it to the prototype (initializing = = True), nothing will happen and the Init method will not be executed. This is done to avoid executing the Init method every time the constructor method is invoked. (var prototype = new This ());.

Copy Code code as follows:

Fntest =/xyz/.test (function () {xyz;})? /\b_super\b/:/.*/;

The purpose of this fntest is to verify that the "_super ()" Call is used in class method. This technique, called "function Decompilation", is also called "function serialisation", which occurs when a function is converted to a string. Many browsers now support the ToString method.

Test function serialisation, Fntest uses an anonymous function Funciton () {xyz;} to set the content to "XYZ" and to use a regular pair of "XYZ" to find it after it has been converted to a string. It will return true (if the browser supports function serialisation) because the functions will be converted to strings so "XYZ" is also part of the string. In this example fntest will return "/\b_super\b/" and the other returns "/.*/" always returns true if the browser does not support function serialisation. (This refers to the fntest.test in the original code) using Fntest Regular, and function serialization techniques, we can easily use the "_super" method if they use, then perform some special methods.  otherwise normal. This particular method is intended to avoid the simultaneous occurrence of the same method in the parent class and the subclass. The parent class will be overwritten.

If the browser does not support Function serialisation will always return true, additional operations will always be performed on _super, resulting in these new methods not being used in _super. This will have some small performance costs. It is guaranteed to work correctly in all browsers.

Copy Code code as follows:

This. Class = function () {};

Creates an empty construction method, which is placed in a global variable. This will be the top-level method of construction. It does not define content, or a prototype object. In addition to the following extends method. This refers to the Window object. Make the Class variable global.

Copy Code code as follows:

Class.extend = function (prop) {//...}

Add the extends method and a simple prop (one object) parameter. It will return the prototype of the new constructed method + the prototype of the parent object;

Copy Code code as follows:

var _super = This.prototype;

Stores the prototype object of the current object in _super. This.prototype is the prototype of the extended object, which can access the parent method where you need it, the variable is called _super, because super is a reserved word. Although it has not yet been applied.

Copy Code code as follows:

Initializing = True;var prototype = new This (); initializing = false;

The instance class object is stored in the prototype variable, but the Init method is not executed. Previously set initializing to True so the Init method is not fire in new class. After the prototype variable is assigned, the initializing is set back to false for the next step to work correctly. (e.g when you want to create a real instance)

Copy Code code as follows:

for (var name in prop) {//...}

Using a For loop, we iterate over the properties and methods in the prop. This property is passed in through the extends method, and in addition to some special handling of _super, we assign the value to the prototype property.

Copy Code code as follows:

Prototype[name] = typeof Prop[name] = = "function" && typeof _super[name] = = "function" && fntest.test (prop [Name]) ? (function (name, FN) {return function () {//Special handling for _super};}) (name, Prop[name]): Prop[name];

When we traverse each object in prop, if satisfied (typeof prop[name] = = "function") (typeof _super[name] = "function") (Fntest.test (Prop[name)) = = True)
We will add new methods to handle new methods and original methods that are bound to the parent class.
The way the code looks like this might seem a little confusing. Use a clear way to view it below.

Copy Code code as follows:

if (typeof prop[name] = = "function" && typeof _super[name] = = "function" && fntest.test (Prop[name))) {Pro Totype[name] = (function (name, FN) {return function () {//Special handling for _super};}) (name, Prop[name]); else {//Just copy the property prototype[name] = Prop[name];}

Another self-executing anonymous function is used in handling the name Prop[name in Super. This closure is not in the bag. When this function is returned, the reference to the variable will be faulted. (e.g It always returns the last of the loop)
Traversing all, we will return a new function that handles the native method (via Super) and the new method.

Copy Code code as follows:

Special handling for Supervar tmp = This._super;this._super = _super[name];var ret = fn.apply (this, arguments); this._su per = Tmp;return ret;

For special handling of super, we first store some parameters that already exist _super properties and classes. stored in temporary TMP, which is to prevent methods that already exist in _super from being overridden
When we're done, we'll assign TMP to This._super so it works.
Next, we assign the _super[name] method to the this._super of the current object, so that when FN is executed via apply This._super () points to the parent class method, which
This in the parent class method also has access to the current object.
Finally, we store the return value in a RET and return the object after the _super is set back.
Here's a simple example, define a simple Foo, create an inherited object Bar:

Copy Code code as follows:

var Foo = Class.extend ({qux:function () {return "Foo.qux";}}); var Bar = Foo.extend ({qux:function () {return "Bar.qux," + This._super ();}});

When the foo.extends is executed, in the Qux method because of the existence of This._super, the Qux of the bar prototype should actually be like this:

Copy Code code as follows:

Bar.prototype.qux = function () {var tmp = This._super; this._super = Foo.prototype.qux; var ret = (function () {return " Bar.qux, "+ This._super ();}). Apply (this, arguments); This._super = tmp; return ret;}

After you complete this step in the script, the constructor is called

Copy Code code as follows:

function Class () {if (!initializing && this.init) this.init.apply (this, arguments);}

This code calls Class to create a new construction method, which is different from the one created earlier. Class, as the local class.extend.  This constructor returns Class.extend calls (for example, previous foo.extends). This constructor is executed after the new Foo () instance.
The constructor will automatically execute the init () method (if present), which is exactly what it says, and this initializing variable controls whether Init is executed.

Copy Code code as follows:

Class.prototype = prototype;

Finally, this prototype returns a blended parent prototype object from the parent class's construction method. (e.g var prototype = new This ()), the result is a for loop in the Extend function.

Class.constructor = Class;
Because we rewrite the entire prototype object, we store the native constructor in this type so that it remains in the default form in the construction method of an instance.

Copy Code code as follows:

Class.extend = Arguments.callee;

Will assign itself, through Arguments.callee, in this case "self" in fact, here we can avoid using Arguments.callee if we modify my native method (e.g Class.extend = function exten D (prop)), we can then use

Copy Code code as follows:

Class.extend = Extend;. return Class;

The instance is then returned with a prototype object, a constructor attribute, a extend method, and an executable method init.!!!

Related Article

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.