Home > Article > Web Front-end > A brief discussion on the analysis of language features of JavaScript_javascript skills
Foreword
In JavaScript, scope, context, closure, function, etc. are the best of the best. For beginner JSers, it is a must for advanced level. For front-end siege engineers, only by calming down and understanding these essences can they write elegant code.
This article aims to summarize important knowledge that is easy to forget and will not cover basic concepts. If you are not familiar with the basic knowledge, just read "The Definitive Guide to JavaScript"~
Language feature function expression
Look at the code snippet first:
What I want to say here is that foo in a function expression can only be referenced inside the function and cannot be referenced outside.
json
Many JavaScript developers mistakenly call JavaScript object literals (JSON Objects). JSON is designed to describe a data exchange format. It also has its own syntax, which is a subset of JavaScript.
{ “prop”: “val” } Such a declaration may be a JavaScript object literal or a JSON string, depending on the context in which it is used. If it is used in a string context (quoted in single or double quotes, or read from a text file), it is a JSON string. If it is used in an object literal context, it is an object literal.
Another thing to know is that JSON.parse is used to deserialize JSON strings into objects, and JSON.stringify is used to serialize objects into JSON strings. Older versions of browsers do not support this object, but you can achieve the same functionality through json2.js.
Prototype
If we completely change the prototype property of the function (by allocating a new object), the reference to the original constructor is lost, because the object we create does not include the constructor property:
Let's take a look at the explanation of constructor on MDN: prototype: Returns a reference to the Object function that created the instance's prototype. Therefore, the prototype reference to the function needs to be restored manually:
However, submitting the prototype attribute will not affect the prototype of the already created object (it will only be affected when the prototype attribute of the constructor changes). That is to say, only newly created objects will have new prototypes, and already created objects will still have new prototypes. Reference to the original old prototype (this prototype can no longer be modified).
Therefore, "dynamically modifying the prototype will affect all objects to have new prototypes" is wrong. The new prototype will only take effect on newly created objects after the prototype is modified. The main rule here is: the prototype of an object is created when the object is created, and cannot be modified to a new object thereafter. If it still refers to the same object, it can be referenced through an explicit prototype in the constructor. After the object is created , only the attributes of the prototype can be added or modified.
Variable object In the function execution context, VO (variable object) cannot be directly accessed. At this time, the activation object (activation object) plays the role of VO. The active object is created when entering the function context and is initialized through the arguments attribute of the function. The value of the arguments attribute is the Arguments object:
When entering the execution context (before code execution), VO already contains the following attributes: 1. All formal parameters of the function (if we are in the function execution context);
•All function declarations (FunctionDeclaration, FD);
•All variable declarations (var, VariableDeclaration);
Another classic example:
According to the specification, function declarations are filled in when entering the context; there is also a variable declaration "x" when entering the context, then as we said above, the variable declaration follows the function declaration and form in sequence After parameter declaration, and during this entering context stage, variable declaration will not interfere with function declarations or formal parameter declarations of the same name that already exist in VO. Compared with simple attributes, variables have an attribute: {DontDelete}. The meaning of this attribute is that the variable attribute cannot be directly deleted using the delete operator.
This In a function context, this is provided by the caller and is determined by the way the function is called. If the left side of the calling bracket () is a value of reference type, this will be set to the base object of the reference type value. In other cases (any other properties different from the reference type), this value will be null. However, there is no actual situation where the value of this is null, because when the value of this is null, its value will be implicitly converted to a global object.
In this example, we have a function object but not a reference type object (it is not an identifier, nor a property accessor), and accordingly, the this value is ultimately set to the global object.
The problem is that in the following three calls, after applying certain operations, the value on the left side of the call bracket is no longer a reference type.
•The first example is obvious - an obvious reference type. The result is that this is the base object, which is foo.
• In the second example, the group operator does not apply, think of the methods mentioned above that get the actual value of an object from a reference type, such as GetValue. Correspondingly, in the return of the group operation - we still get a reference type. This is why the this value is set to the base object again, which is foo.
•In the third example, unlike the group operator, the assignment operator calls the GetValue method. The returned result is a function object (but not a reference type), which means this is set to null and the result is a global object.
• The same goes for the fourth and fifth - the comma operator and the logical operator (OR) call the GetValue method, and accordingly we lose the reference and get the function. And set it to global again.
As we know, local variables, internal functions, and formal parameters are stored in the activation object of a given function.
The active object is always returned as this, and the value is null - (that is, AO.bar() in pseudo code is equivalent to null.bar()). Here we return to the example described above again, with this set to the global object.
Scope chain
The scope attribute of a function created through the function constructor is always the only global object.
One important exception involves functions created via function constructors.
Also:
What happens when entering context? The identifiers "x" and "y" have been added to the variable object. In addition, make the following modifications during the code running phase:
•x = 10, y = 10;
•The object {x:20} is added to the front of the scope;
•Inside the with, the var declaration is encountered, and of course nothing is created, because in When entering the context, all variables have been parsed and added;
• In the second step, only the variable "x" is modified, actually the "x" in the object is now parsed and added to the front of the scope chain, "x" is 20 and becomes 30;
•There is also a modification of the variable object "y". After being parsed, its value also changes from 10 to 30;
•In addition, after the with statement is completed, Its specific object is removed from the scope chain (the changed variable "x" - 30 is also removed from that object), that is, the structure of the scope chain is restored to the state before with was strengthened.
•In the last two alerts, the "x" of the current variable object remains the same, and the value of "y" is now equal to 30, which has changed during the with statement run.
Function
Questions about parentheses
Let’s look at the question: ‘ Why do I have to surround a function with parentheses when calling it immediately after it is created? ', the answer is: the restriction of expression sentences is like this.
According to the standard, an expression statement cannot start with a brace { because it is difficult to distinguish it from a code block. Similarly, it cannot start with a function keyword because it is difficult to distinguish it from a function declaration. That is, so if we define a function that executes immediately, immediately after its creation, we call it like this:
We used function declarations. For the above two definitions, the interpreter will report an error when interpreting, but there may be many reasons. If it is defined in global code (that is, program level), the interpreter will treat it as a function declaration because it starts with the function keyword. In the first example, we will get a SyntaxError because the function declaration has no name. (We mentioned earlier that function declarations must have names). In the second example, we have a function declaration named foo that is created normally, but we still get a syntax error - a grouping operator error without any expression. It is indeed a grouping operator after the function declaration, not the parentheses used in a function call. So if we declare the following code:
The simplest way to create an expression is to use grouping operator brackets. What is put inside is always an expression, so there will be no ambiguity when the interpreter interprets it. This function will be created during the code execution phase, executed immediately, and then automatically destroyed (if there is no reference)
The above code is what we call enclosing an expression in parentheses and then calling it through (1). Note that for the following function that is executed immediately, the surrounding parentheses are not necessary, because the function is already at the position of the expression, and the parser knows that it is dealing with the FE that should be created during the function execution phase, so that it is called immediately after the function is created. function.
As we can see, foo.bar is a string and not a function. The function here is only used to initialize this property based on the conditional parameters - it is created and called immediately.
1. Therefore, the complete answer to the question "About parentheses" is as follows:
2. When the function is not in the expression position, the grouping operator parentheses are necessary - that is, manually The function is converted into FE.
3. If the parser knows that it is dealing with FE, there is no need to use parentheses.
Free variables:
Static scope of closure:
Theory: Because of the scope chain, all functions are closures (regardless of function type: anonymous functions, FE, NFE, and FD are all closures). From a practical perspective: The following functions are considered closures: * It still exists even if the context in which it was created has been destroyed (for example, the inner function returns from the parent function)
* References a free variable
in the codeFinally:
ECMAScript is an object-oriented language that supports prototype-based delegated inheritance.