SoFunction
Updated on 2025-04-10

About JavaScript's ways to define classes and objects

Let's take a look at this example:
Copy the codeThe code is as follows:

var a = 'global';
(function () {
alert(a);
var a = 'local';
})();


What do you think is the output result when you first see this example? ‘global’? Or ‘local’? Actually, none of them are. The output is undefined, so don't be confused. My off-topic talk is just to talk about this.
It's actually very simple. You will understand by looking at the JavaScript running mechanism. We can regard this phenomenon as a "pre-declaration". But if you look at it a little bit, you will understand it more thoroughly.
This actually involves the object attribute binding mechanism. Because all JavaScript functions are an object. The variable declared in the function can be regarded as "similar properties" of this object. The binding of object attributes is divided into "early binding" and "late binding" in the language.

【Early binding】
It refers to defining its properties and methods before instantiating an object. It can be converted into machine code in advance when parsing the program. Usually strongly typed languages ​​such as C++, java, etc. are all premature binding mechanisms. And JavaScript is not a strongly typed language. It uses the "late binding" mechanism.
【Late Binding】
It means that before the program runs, there is no need to check the object type, just check whether the object supports features and methods. You can perform a large number of operations on an object before binding without any punishment.
We can use the "late binding" mechanism to explain the "predeclaration" phenomenon that appears in the above code. In the scope of a function, all variables are "late bound". That is, the declaration is top-level. So the above code is consistent with the following:
Copy the codeThe code is as follows:

var a = 'global';
(function () {
var a;
alert(a);
a = 'local';
})();

Only a is declared before alert(a) and no value is assigned. So the result can be imagined.

<!-- The end of the topic -->
RT: What this article is about is that in JavaScript, I know several ways to define classes and objects: <! -- Statement: Most of the following content comes from "JavaScript Advanced Programming", but the personal narrative method is different -->
【Direct measurement method】
Using direct quantities to build objects is the most basic way, but it also has many disadvantages.
Copy the codeThe code is as follows:

var Obj = new Object;
= 'sun';
= function() {
alert('');
}

We build an object Obj, which has a property name and a method showName. But what if we want to build another similar object? Do you 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 output of the pipeline we want the specific type of result.
【Factory Method】
Copy the codeThe code is as follows:

function createObj(name) {
var tempObj = new Object;
= name;
= function () {
alert();
};
return tempObj;
}
var obj1 = createObj('obj_one');
var obj2 = createObj('obj_two');

Many people do not regard this kind of factory function as a form of building objects. Part of the reason is semantics: that is, it is not as formal as it is built with the operator new. There is another bigger reason, because this factory creates a new function showName() every time it produces an object, that is, each object has a different version, but in fact they share the same function.
Some people can avoid this problem by defining showName outside the factory function and pointing to the method through the attribute:
Copy the codeThe code is as follows:

function showName () {
alert();
}
function createObj(name) {
var tempObj = new Object;
= name;
= showName;
return tempObj;
}
var obj1 = createObj('obj_one');
var obj2 = createObj('obj_two');

Unfortunately, this method makes the showName() function not look like an object.
【Constructor method】
This method is to solve the first problem of the above factory function, that is, the problem of no new operator. But it still cannot solve the second problem. Let's take a look.
Copy the codeThe code is as follows:

function Obj(name) {
= name;
= function () {
alert();
}
}
var obj1 = new Obj('obj_one');
var obj2 = new Obj('obj_two');

Its advantage is that it does not need to create a new object in the constructor, because an object will be automatically created when the new operator is executed, and this object can only be accessed through this. So we can directly assign values ​​to this object through this. And no need to return, because this points to the return value that defaults to the constructor.
At the same time, using the new keyword to create the object we want does it feel more "formal".
Unfortunately, it still cannot solve the problem of re-generating method functions, which is the same as factory functions.

【Prototype method】
Compared with the above methods, this method has a great advantage, which is that it solves the problem that the method function will be generated multiple times. It takes advantage of the prototype property of the object. We rely on prototypes to override object instances.
Copy the codeThe code is as follows:

var Obj = function () {}
= 'me';
= function () {
alert();
}
var obj1 = new Obj();
var obj2 = new Obj();

We rely on prototypes to rewrite the constructor. Whether it is properties or methods, they are used to refer to the newly created objects through prototypes, so they will only be created once. Unfortunately, there are two fatal problems in this approach:
1. There is no way to write the desired attribute when building the object, because the prototype is outside the scope of the constructor, and there is no way to write the attribute value when the object is created by passing parameters. Values ​​can only be rewrite after the object is created.
2. The fatal problem is that when the property points to an object, the object is shared by multiple instances. Consider the following code:
Copy the codeThe code is as follows:

var Obj = function () {}
= 'me';
= new Array('A', 'B');
= function () {
alert();
}
var obj1 = new Obj();
var obj2 = new Obj();
('C');
alert(); // A,B,C
alert(); //A,B,C

Yes, when the flag attribute points to the object, 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 wonder whether we should combine the [constructor method] and the [prototype method] to complement each other. . .

【Constructor and prototype mixing method】
We let the attributes be created in the constructor form, and the method is created in the prototype form:
Copy the codeThe code is as follows:

var Obj = function (name) {
= name;
= new Array('A', 'B');
}
= {
showName : function () {
alert();
}
}
var obj1 = new Obj();
var obj2 = new Obj();
('C');
alert(); // A,B,C
alert(); //A,B

This method effectively combines the advantages of prototypes and constructors, and is currently the most used and has the least side effects.
However, some guys who pursue perfection are not satisfied because they have not met their requirements visually, because the process of creating methods through prototypes visually makes people feel that they are not very similar to instance methods (especially for developers of traditional OOP languages).
Therefore, we can make the prototype active and add it to the constructor, so that the constructor is visually more unified. This series of processes can be completed with just one judgment.
Copy the codeThe code is as follows:

var Obj = function (name) {
= name;
= new Array('A', 'B');
if (typeof Obj._init == 'undefined') {
= {
showName : function () {
alert();
}
};
Obj._init = true;
}
}

As mentioned above, use _init as a flag to determine whether a method has been created for the prototype. If so, then no more execution. In fact, there is no change in nature. The method is still created through prototypes. The only difference is that this constructor seems to be "unified".
However, this dynamic prototype method is problematic, and it is not delved into it in "JavaScript Advanced Programming". When creating the first object, it will be inaccessible because the prototype has not been built before the object is instantiated. Therefore, the first object cannot access the prototype method. At the same time, this method will also have problems in subclass inheritance.
Regarding the solution, I will explain it in the next article.

In fact, in terms of convenience of use, I personally think there is no need to make this judgment. . . Haha ^_^