1. Several Basic Concepts
Why?
When discussing inheritance, we have already listed some basic concepts that are closely related to encapsulation. Today we will discuss the basic concepts, it is mainly related to inheritance and polymorphism, but they are also related to encapsulation.
1.1 Definition and assignment
Variable definition refers to the use
Var;
Declare variables in this form.
Function definition refers to the use
Function (...){...}
Declare a function in this form.
Var a = 1;
Is two processes. The first process is to define variable a, and the second process is to assign values to variable.
Similarly
Var a = function (...){};
The first process is to define variable a and an anonymous function. The second process is to assign an anonymous function to variable.
Variable definition and function definition are completed before the execution of the entire script, while variable assignment is completed in the execution phase.
The function of a variable definition is to specify its scope for the declared variable. The variable definition does not give the initial value of the variable, any variables that are not defined and directly used, or variables that are defined but not assigned values, their values are all undefined.
In addition to declaring the scope of a function, the function definition also defines the function body structure. This process is recursive. That is to say, the definition of the function body includes the definition of variables and functions in the function body.
Through the following example, we can better understand this point:
Copy codeThe Code is as follows:
Alert ();
Alert (B );
Alert (c );
Var a = "";
Function (){}
Function B (){}
Var B = "B ";
Var c = "c ";
Var c = function (){}
Alert ();
Alert (B );
Alert (c );
Guess what the execution result of this program is? Run the following command to see if it is the same as what you think. If it is the same as what you think, it means that you have understood the above.
The results of this program are very interesting. Although the first alert (a) is at the beginning, you will find that the output value is actually function, the function definition is indeed completed before the entire program is executed.
Let's look at B. function B is defined before variable B, but the first alert (B) still outputs function B, A variable definition does not do anything about a variable. It only declares its scope and does not overwrite the function definition.
Finally, in c, the first alert (c) output is undefined, which means var c = function () {} is not defined for function c, just define a variable c and an anonymous function.
Let's look at the second alert (a). You will find that the output is actually a, which means that the value assignment statement is indeed completed during execution. Therefore, it overwrites the definition of function.
The second alert (B) is of course the same. The output is B, which means that no matter whether the value assignment statement is written before the function definition or after the function definition, A value assignment to a variable with the same name as a function always overwrites the function definition.
The second alert (c) Outputs function () {}. This indicates that the value assignment statement is executed sequentially, and the subsequent value assignment overwrites the previous value assignment, whether the value is a function or another object.
After understanding the content mentioned above, I think you should know when to use function x (..){...}, When should I use var x = function (...) {...} Right?
Finally, let us also remind you that if the variable definition and Function Definition appear in eval, they are completed in the execution phase. Therefore, do not use eval! In addition, even if you want to use eval, do not use local variables and local methods in it!
1.2 this and execution Context
We have already touched this before we discussed encapsulation. In the discussion of encapsulation, we can see that this represents the instantiated object of the class where this is located. Is that true?
Let's take a look at the following example in the pipeline:
Copy codeThe Code is as follows:
Var x = "I'm a global variable! ";
Function method (){
Alert (x );
Alert (this. x );
}
Function class1 (){
// Private field
Var x = "I'm a private variable! ";
// Private method
Function method1 (){
Alert (x );
Alert (this. x );
}
Var method2 = method;
// Public field
This. x = "I'm a object variable! ";
// Public method
This. method1 = function (){
Alert (x );
Alert (this. x );
}
This. method2 = method;
// Constructor
{
This. method1 (); // I'm a private variable!
// I'm a object variable!
This. method2 (); // I'm a global variable!
// I'm a object variable!
Method1 (); // I'm a private variable!
// I'm a global variable!
Method2 (); // I'm a global variable!
// I'm a global variable!
Method1.call (this); // I'm a private variable!
// I'm a object variable!
Method2.call (this); // I'm a global variable!
// I'm a object variable!
}
}
Var o = new class1 ();
Method (); // I'm a global variable!
// I'm a global variable!
O. method1 (); // I'm a private variable!
// I'm a object variable!
O. method2 (); // I'm a global variable!
// I'm a object variable!
Why is this?
Let's take a look at the execution context. What is the execution context?
If a method is being executed, the execution context is the object attached to the method, the created object is the execution context.
If a method does not explicitly attach to an object during execution, its execution context is a global object (top-level object), but not necessarily a global object. Global objects are determined by the current environment. In the browser environment, the Global object is the window object.
Global variables and global functions that are defined outside all functions are attached to global objects. Local variables and local functions defined in the function are not attached to any objects.
Is the execution context related to the variable scope?
The execution context is different from the variable scope.
When a function is assigned to another variable, the scope of the variable used inside the function will not change, however, its execution context changes to the object attached to this variable (if this variable has an object attached to it ).
The call and apply methods on the Function prototype can change the execution context, but do not change the variable scope.
To understand the above words, you only need to remember one thing:
The scope of a variable is determined at the time of definition and will never change. The execution context is determined at the time of execution and can be changed at any time.
In this way, we can easily understand the example above. This. when executing the statement method1 () (note that the function body has not been entered here), the object is being created, and the current execution context is the object being created, therefore, this points to an object that is currently being created. method1 () when this method is executed (this refers to the function body), the object attached to the method being executed is also the object being created, so it contains this. this of x is also the same object, so the output you see is I'm a object variable! .
While executing the method1 () function (after entering the function body), method1 () does not explicitly attach to an object, although it is defined in class1, however, it is not attached to class1, nor to objects after class1 instantiation, but its scope is limited to class1. Therefore, its ancillary object is actually a global object, so when it is executed to alert (this. x), this. x is the value defined in the global environment as "I'm a global variable!" .
Although method2 () is defined in class1, method () is defined outside class1. When method is assigned to method2, the scope of method is not changed, when executing method2, it is still executed in the scope defined by method. Therefore, what you see is two I'm a global variable! Output. Similarly, when this. method2 () is called, alert (x) Outputs I'm a global variable! This is also the reason.
Because call changes the execution context, this. x changes to I'm a object variable when method1.call (this) and method2.call (this) are used !. However, it cannot change the scope, so the result of x is the same as that of calling without using the call method.
And we will execute o. in method1 (), alert (x) does not use this to indicate the execution context of x. Then, x indicates the recently defined variable in the scope of the currently executed function. Therefore, the output is I'm a private variable !. Final output I'm a object variable! I don't want to say that everyone knows why?
2 Inheritance and Polymorphism
2.1 starting from Encapsulation
As we mentioned earlier, the purpose of encapsulation is to hide data.
At a deeper level, encapsulation in javascript has the following benefits:
1. Stealth implementation details. when the implementation of the private part is completely rewritten, the caller's behavior does not need to be changed. This is also the main purpose of encapsulation for other object-oriented languages.
2. In javascript, local variables and local functions are faster to access. Therefore, private fields are encapsulated with local variables. Encapsulating private methods with local methods can improve script execution efficiency.
3. For javascript compression obfuscators (as far as I know, the best javascript analysis, compression, and obfuscators are JSA), both local variables and local function names can be replaced, however, the global variables and global function names cannot be replaced (in fact, this is also true for javascript script parsers ). Therefore, for open-source or non-open-source javascript programs, when private fields and private methods use encapsulation technology, you can define long enough ideographic names for them when writing code, code readability is increased, and they can be replaced with some very short names (generally single character names) during release, so that they can be fully compressed and obfuscated. And reduces bandwidth usage, and can truly hide details.
Therefore, encapsulation is very useful for javascript!
So what is the purpose of javascript inheritance?
2.2 why inherit
In other object-oriented programming languages, apart from reducing repeated code writing, inheritance is most useful for polymorphism. This is especially true for strong-type languages:
1. In a strongly typed language, a variable cannot be assigned two values of different types, unless these two types are compatible with the type of the variable, this compatible relationship is implemented by inheritance.
2. In a strongly typed language, methods cannot be directly expanded or rewritten for an existing type. To expand a type, the only method is to inherit it, in its subclass, it is expanded and rewritten.
Therefore, for strong object-oriented languages, the implementation of polymorphism depends on the implementation of inheritance.
For the javascript language, inheritance is less important for implementing polymorphism:
1. In javascript, a variable can be assigned a value of any type and can call methods of the same name on any type of object in the same way.
2. In javascript, existing types can be expanded and rewritten directly through prototype.
Therefore, in javascript, inheritance is mainly used to reduce the compilation of repeated code.
The two inheritance methods we will discuss next may be familiar to everyone. One is the prototype Inheritance Method and the other is the inheritance method, which will not produce any side effects. We mainly discuss the nature of the two methods and what needs attention.
2.3 prototype Inheritance Law
In javascript, each class (function) has a prototype. Members of this prototype are passed to the instantiated object of this class when the class is instantiated. There is no prototype on the instantiated object, but it can be used as the prototype of another class (function). When the class is instantiated with this object as the prototype, the members on the object will be passed to the instantiated object of the class as the prototype. This is the essence of prototype inheritance.
Prototype inheritance is also an inheritance method used by many native objects in javascript.
Copy codeThe Code is as follows:
Function parentClass (){
// Private field
Var x = "I'm a parentClass field! ";
// Private method
Function method1 (){
Alert (x );
Alert ("I'm a parentClass method! ");
}
// Public field
This. x = "I'm a parentClass object field! ";
// Public method
This. method1 = function (){
Alert (x );
Alert (this. x );
Method1 ();
}
}
ParentClass. prototype. method = function (){
Alert ("I'm a parentClass prototype method! ");
}
ParentClass. staticMethod = function (){
Alert ("I'm a parentClass static method! ");
}
Function subClass (){
// Private field
Var x = "I'm a subClass field! ";
// Private method
Function method2 (){
Alert (x );
Alert ("I'm a subClass method! ");
}
// Public field
This. x = "I'm a subClass object field! ";
// Public method
This. method2 = function (){
Alert (x );
Alert (this. x );
Method2 ();
}
This. method3 = function (){
Method1 ();
}
}
// Inherit
SubClass. prototype = new parentClass ();
SubClass. prototype. constructor = subClass;
// Test
Var o = new subClass ();
Alert (o instanceof parentClass); // true
Alert (o instanceof subClass); // true
Alert (o. constructor); // function subClass (){...}
O. method1 (); // I'm a parentClass field!
// I'm a subClass object field!
// I'm a parentClass field!
// I'm a parentClass method!
O. method2 (); // I'm a subClass field!
// I'm a subClass object field!
// I'm a subClass field!
// I'm a subClass method!
O. method (); // I'm a parentClass prototype method!
O. method3 (); // Error !!!
SubClass. staticMethod (); // Error !!!
The above example shows how to use the prototype inheritance method to implement inheritance.