JavaScript modularity: Encapsulation (closures), Inheritance (prototypes) Introduction _javascript Tips

Source: Internet
Author: User
Tags closure object object

While JavaScript is inherently casual, the language is becoming more and more often sat as the browser can do more and more things. In complex logic, JavaScript needs to be modular, modules need to be encapsulated, leaving only interfaces for outside calls. Closures are the key to implementing module encapsulation in JavaScript, and are also difficult for many beginners to understand. At first, I was lost in confusion. Now, I am confident that I have a more in-depth understanding of this concept. To facilitate understanding, the article attempts to encapsulate a simpler object.

We tried to maintain a counter object ticker on the page, which maintains a value of N. With the user's action, we can add a count (add n plus 1), but not reduce n or directly change N. Also, we need to query this value from time to time.

Portal wide JSON-style modularity

One way to open a portal is to:

Copy Code code as follows:

var ticker = {
n:0,
Tick:function () {
this.n++;
},
};

This way of writing nature, and indeed effective, we need to add a count when we call the Ticker.tick () method, the number of queries needed to access the TICKER.N variable. But the downside is obvious: the user of the module is allowed to change n freely, such as calling ticker.n--or Ticker.n=-1. We do not encapsulate ticker, and N and Tick () appear to be "members" of the ticker, but their accessibility is as global as ticker (if ticker is globally variable). In terms of encapsulation, this modular approach is a little bit more ridiculous than the following (although this is a little bit more for some simple applications).

Copy Code code as follows:

var ticker = {};
var tickern = 0;
var Tickertick = function () {
tickern++;
}

Tickertick ();

It is noteworthy that, in tick (), I am accessing this.n--this is not because N is a member of ticker, but because ticker is called tick (). In fact it would be better to write TICKER.N here, because if you call tick () it's not ticker, it's something else, like:

Copy Code code as follows:

var func = Ticker.tick;
Func ();

At this point, the call to tick () is actually window, and the function executes with an error attempting to access WINDOW.N.

In fact, this "open door" modular approach is often used to organize JSON-style data rather than programs. For example, we could pass the following JSON object to a function of ticker to determine that the ticker count starts at 100, each time 2.

Copy Code code as follows:

var config = {
NSTART:100,
Step:2
}

Scope Chains and closures
Look at the following code, note that we have implemented the incoming config to customize the ticker.

Copy Code code as follows:

function Ticker (config) {
var n = config.nstart;
function tick () {
n + = Config.step;
}
}
Console.log (TICKER.N); ->undefined

You may wonder, how ticker from the object into a function? This is because only functions in JavaScript have scope and cannot access variables inside functions outside of the function body. Ticker () external access ticker.n get undefined, while tick () access to n is not a problem. From tick () to ticker () to global, this is the scope chain in JavaScript.

But there is a problem, that is--how to call tick ()? The scope of the ticker () also obscures the tick (). There are two ways to fix this:

·1) will need to invoke the method as the return value, as we will increment the N method as the return value of ticker ();
2) Sets the outer scope variable, as we set the GETN in ticker ().

Copy Code code as follows:

var getn;
function Ticker (config) {
var n = config.nstart;
GETN = function () {
return n;
};
return function () {
n + = Config.step;
};
}

var tick = ticker ({nstart:100,step:2});
Tick ();
Console.log (GETN ()); ->102

See, at this point, the variable n is in the "closure" and cannot be accessed directly outside the ticker (), but it can be observed or manipulated in two ways.

In the first paragraph of this section of code, after the ticker () method executes, N and tick () are destroyed until the next time the function is called, but in the second code, when ticker () executes, n is not destroyed because tick () and GETN () may access it or change it , the browser is responsible for maintaining N. My understanding of "closure" is to ensure that N is a mechanism that is in the function scope, which is maintained after the function has been executed, and that variables that may be accessed by other means are not destroyed.

But I still don't feel quite right? What if I need to maintain two objects with the same functionality Ticker1 and Ticker2? Ticker () There is only one, can't you write it again?

The new operator and the constructor
If a function is called with the new operator, a new object is created and the function is invoked using that object. In my understanding, the construction of T1 and T2 is the same in the following code.

Copy Code code as follows:

function MyClass () {}
var T1 = new MyClass ();
var t2 = {};
T2.func = MyClass;
T2.func ();
T2.func = undefined;

Both T1 and T2 are newly constructed objects, and MyClass () is the constructor. Similarly, ticker () can be rewritten.

Copy Code code as follows:

function Ticker (config) {
var n = config.nstart;
THIS.GETN = function () {
return n;
};
This.tick = function () {
n + = Config.step;
}
}

var ticker1 = new Ticker ({nstart:100,step:2});
Ticker1.tick ();
Console.log (TICKER1.GETN ()); ->102
var ticker2 = new Ticker ({nstart:20,step:3});
Ticker2.tick ();
Ticker2.tick ();
Console.log (TICKER2.GETN ()); ->26

In practice, constructors use uppercase. Note that ticker () is still a function, not a pure object ("pure" because the function is actually an object, ticker () is the function object), the closure is still valid, we cannot access the TICKER1.N.

Prototype prototype and inheritance
The above ticker () is still defective, that is, Ticker1.tick () and Ticker2.tick () are independent of each other! See, every call to ticker () with the new operator, a new object is generated and a new function is generated to bind to this new object, and each new object is constructed, and the browser is going to open up a space to store the variables in the tick () itself and tick (), which is not what we expected. We expect Ticker1.tick and Ticker2.tick to point to the same function object.

This requires the introduction of prototypes.

In JavaScript, other objects have a prototype property, except the object object, which points to another object. The "other object" still has its prototype object and forms a prototype chain that eventually points to object. When a method is invoked on an object, if it is found that the object does not have a specified method, the method is searched at once on the prototype chain until the object.

A function is also an object, so the function also has a prototype object. When a function is declared (that is, when the function object is defined), a new object is generated, and the object's prototype attribute points to the object, and the object's constructor attribute points to the function object.

A new object constructed from a constructor that points to a prototype object of the constructor. So we can add functions to the stereotype object of the constructor, which is not dependent on the Ticker1 or Ticker2, but on the ticker.

You might do this:

Copy Code code as follows:

function Ticker (config) {
var n = config.nstart;
}
TICKER.prototype.getN = function{
Attention:invalid implementation
return n;
};
TICKER.prototype.tick = function{
Attention:invalid implementation
n + = Config.step;
};

Please note that this is an invalid implementation. Because the method of the prototype object cannot access the contents of the closure, that is, the variable N. The TICK () method can no longer access to n after it is run, and the browser destroys N. In order to access the contents of the closure, the object must have a concise, instance-dependent approach to accessing the contents of the closure and then defining a complex public method on its prototype to implement the logic. In fact, the tick () method in the example is simple enough, so let's put it back in the ticker. The following implements a more complex method, Ticktimes (), which will allow the caller to specify the number of times to invoke tick ().

Copy Code code as follows:

function Ticker (config) {
var n = config.nstart;
THIS.GETN = function () {
return n;
};
This.tick = function () {
n + = Config.step;
};
}
TICKER.prototype.tickTimes = function (n) {
while (n>0) {
This.tick ();
n--;
}
};
var ticker1 = new Ticker ({nstart:100,step:2});
Ticker1.tick ();
Console.log (TICKER1.GETN ()); ->102
var ticker2 = new Ticker ({nstart:20,step:3});
Ticker2.ticktimes (2);
Console.log (TICKER2.GETN ()); ->26

This ticker is very good. It encapsulates N and cannot be changed directly from outside of an object, and complex function ticktimes () is defined on the prototype, which manipulate the data in the object by calling the instance's small function.

Therefore, in order to maintain the encapsulation of the object, my advice is to decouple the operation of the data into the smallest possible cell function, defined in the constructor as relying on the instance (many places also called "private"), and the complex logic is implemented on the prototype (that is, "public").

Finally, say something about inheritance. In fact, when we define a function on a prototype, we are already using inheritance! The inheritance in JavaScript is more than in C + + ... Uh...... Simple, or shabby. In C + +, we might define a animal class to represent an animal, and then define the bird class to inherit the animal class to represent the birds, but I want to discuss not such inheritance (although such inheritance can also be implemented in JavaScript); The inheritance I want to discuss in C + + will be, define a Animal class, and then instantiates a MyAnimal object. Yes, this is instantiated in C + +, but it is treated as inheritance in JavaScript.

JavaScript does not support classes, and browsers do not bother to take care of what objects are, what class they are, and what structure they should have. In our case, ticker () is a function object that we can assign (ticker=1) to delete (ticker=undefined), but because there are currently Ticker1 and ticker2 two objects that are called by the new operator, Ticker () acts as a constructor, and the Ticker.prototype object acts as a function of the class.

The above is what I understand the JavaScript modular approach, if you are also a beginner, I hope to help you. If there is a mistake, please point it out.

Author: The owner of one leaf Zhai
Source: Www.cnblogs.com/yiyezhai

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.