You can take a look at this example:
var a = 'global' ;
(function () {
alert(a);
var a = 'local';
})();
Everyone first When you see this example, what do you think the output is? 'global'? Or 'local'? In fact, it is not the case. The output is undefined. Don’t be confused. My digression is just to talk about this thing.
In fact, it is very simple. You will understand it if you take a look at the JavaScript operating mechanism. We can think of this phenomenon as "pre-statement". But if you dig a little deeper, you will understand it more clearly.
This actually involves the object property binding mechanism. Because all JavaScript functions are an object. Variables declared in a function can be regarded as "similar properties" of this object. The binding of object properties is divided into "early binding" and "late binding" in the language.
[Early Binding]
refers to defining the properties and methods of an object before instantiating it. It can be converted to machine code in advance when parsing the program. Commonly typed languages such as C, Java, etc. all use early binding mechanisms. And JavaScript is not a strongly typed language. It uses a "late binding" mechanism.
【Late Binding】
means that before running the program, there is no need to check the object type, just check whether the object supports properties and methods. A large number of operations can be performed on the object before binding without penalty.
The "pre-declaration" phenomenon in the above code can be explained by the "late binding" mechanism. Within a function's scope, all variables are "late bound". That is, the statement is top-level. So the above code is consistent with the following:
var a = 'global';
(function () {
var a;
alert(a);
a = 'local';
})();
Before alert(a), only a was declared without assigning a value. So the results can be imagined.
RT: What this article is going to talk about is the several ways I know of defining classes and objects in JavaScript: < ! -- Statement: Most of the following content comes from "JavaScript Advanced Programming", but the personal narrative method is different -- >
【Direct Quantity Method】
Using direct quantities to construct objects is the most basic way, but There are also many disadvantages.
var Obj = new Object;
Obj.name = 'sun';
Obj.showName = function() {
alert('this.name');
}
We construct an object Obj, which has An attribute name and a method showName. But what if we want to build another similar object? Do we have to repeat it again?
NO! , we can implement it with a factory function that returns an object of a specific type. Just like a factory, the pipeline outputs the specific type of results we want.
【Factory method】
function createObj(name) {
var tempObj = new Object;
tempObj.name = name;
tempObj.showName = function () {
alert(this.name);
};
return tempObj ;
}
var obj1 = createObj('obj_one');
var obj2 = createObj('obj_two');
Many people don’t use this factory function As a form of constructing objects. Part of the reason is semantics: it's not as formal as building with operator new. There is another bigger reason, because every time this factory produces an object, it creates a new function showName(), that is, each object has a different version, but in fact they share the same function.
Some people define showName outside the factory function, and then point to the method through attributes, which can avoid this problem:
function showName () {
alert(this.name);
}
function createObj(name) {
var tempObj = new Object ;
tempObj.name = name;
tempObj.showName = showName;
return tempObj;
}
var obj1 = createObj('obj_one');
var obj2 = createObj( 'obj_two');
Unfortunately, this method makes the showName() function not look like a method of the object.
[Constructor method]
This method is to solve the first problem of the factory function above, that is, the problem of no new operator. But it still cannot solve the second problem. Let's take a look.
function Obj(name) {
this.name = name;
this.showName = function () {
alert(this.name);
}
}
var obj1 = new Obj('obj_one');
var obj2 = new Obj('obj_two');
The advantage is that there is no need to create a new object in the constructor, because the new operator will automatically create an object when it is executed, and only through this to access this object. So we can assign a value to this object directly through this. And there is no need to return, because this points to the return value of the constructor by default.
At the same time, using the new keyword to create the object we want feels more "formal".
Unfortunately, it still cannot solve the problem of repeatedly generating method functions, which is the same as factory functions.
[Prototype method]
Compared with the above methods, this method has a great advantage, that is, it solves the problem of method functions being generated multiple times. It makes use of the prototype property of the object. We rely on prototypes to override object instances.
var Obj = function () {}
Obj .prototype.name = 'me';
Obj.prototype.showName = function () {
alert(this.name);
}
var obj1 = new Obj();
var obj2 = new Obj();
We rely on the prototype to rewrite the constructor. Both properties and methods are given to the newly created objects through prototype references, so they will only be created. once. Unfortunately, this method has two fatal problems:
1. There is no way to write the desired properties when the object is constructed, because the prototype is outside the scope of the constructor, and there is no way to write the property values when the object is created by passing parameters. Values can only be overridden after the object has been created.
2. The fatal problem is that when a property points to an object, the object will be shared by multiple instances. Consider the following code:
var Obj = function () { }
Obj.prototype.name = 'me';
Obj.prototype.flag = new Array('A', 'B');
Obj.prototype.showName = function () {
alert(this.name);
}
var obj1 = new Obj();
var obj2 = new Obj();
obj1.flag.push('C');
alert(obj1.flag); // A,B,C
alert(obj2.flag); //A,B,C
Yes, when the flag attribute points to the object , then both instances obj1 and obj2 share it, even if we only change the flag attribute of obj1, its change is still visible in instance obj2.
Faced with this problem, we have to think about whether we should combine [constructor method] and [prototype method] to make them complementary. . .
[Constructor and prototype mixed method]
We let the properties be created using the constructor method, and the methods can be created using the prototype method:
var Obj = function (name) {
this.name = name;
this.flag = new Array(' A', 'B');
}
Obj.prototype = {
showName : function () {
alert(this.name);
}
}
var obj1 = new Obj();
var obj2 = new Obj();
obj1.flag.push('C');
alert(obj1.flag); // A,B,C
alert(obj2.flag); //A,B
This method effectively combines the advantages of prototypes and constructors. It is currently the most used method and has the least side effects.
However, some people who pursue perfection are still not satisfied because visually they have not yet met their requirements, because the process of creating methods through prototypes still visually makes people feel that it does not look like instance methods (especially For developers of traditional OOP languages. )
Therefore, we can make the prototype active and add it to the constructor to make the constructor more visually unified. This series of processes can be completed with only one judgment.
var Obj = function (name) {
this.name = name;
this.flag = new Array('A', 'B');
if (typeof Obj. _init == 'undefined') {
Obj.prototype = {
showName : function () {
alert(this.name);
}
};
Obj._init = true;
}
}
As above, use _init as a flag to determine whether a method has been created for the prototype. If so then it will not be executed. In fact, there is no change in essence. The method is still created through the prototype. The only difference is that this constructor looks "unified".
However, there are problems with this dynamic prototyping method, which is not discussed in depth in "JavaScript Advanced Programming". When you create the first object, the prototype is not built before the object is instantiated, so it is not accessible at all. So the first object cannot access the prototype method. At the same time, this method will also have problems in subclass inheritance.
I will explain the solution in the next article.
In fact, in terms of ease of use, I personally feel that there is no need to make this judgment. . . Haha ^_^