Analysis on the language features of JavaScript

Source: Internet
Author: User

Preface
In JavaScript, scopes, contexts, closures, and functions are the essence. For Junior JSer, it is an advanced necessity. For front-end captors, they can write elegant code only by keeping calm and understanding the essence.

This article aims to summarize important knowledge that is easy to forget and will not talk about basic concepts. If you are not familiar with the basic knowledge, go to the JavaScript authoritative guide ~


Language Feature function expression

First look at the code segment:

Copy codeThe Code is as follows:
[Javascript] view plaincopyprint?
Var f = function foo (){
Return typeof foo; // foo is valid within the internal scope
};
// Foo is used externally and therefore invisible.
Typeof foo; // "undefined"
F (); // "function"
Var f = function foo (){
Return typeof foo; // foo is valid within the internal scope
};
// Foo is used externally and therefore invisible.
Typeof foo; // "undefined"
F (); // "function"

Here, the foo in the function expression can only be referenced inside the function, but cannot be referenced outside the function.


Json

Many JavaScript developers mistakenly call Object Literals as JSON Objects (JSON Objects ). JSON is designed to describe the data exchange format. It also has its own syntax, which is a subset of JavaScript.

A declaration such as {"prop": "val"} may be a JavaScript Object literal or a JSON string, depending on the context in which it is used. If it is used in the string context (with single quotes or double quotes, or read from the text file), it is a JSON string. If it is used in the context of the object literal, that is, the object literal.

Copy codeThe Code is as follows:
[Javascript] view plaincopyprint?
// This Is a json string
Var foo = '{"prop": "val "}';
// This is the object literal
Var bar = {"prop": "val "};
// This Is a json string
Var foo = '{"prop": "val "}';
// This is the object literal
Var bar = {"prop": "val "};

Another thing to know is that JSON. parse is used to deserialize the JSON string into an object, and JSON. stringify is used to serialize the object into a JSON string. The browser of the old version does not support this object, but you can use json2.js to implement the same function.


Prototype

Copy codeThe Code is as follows:
Function Animal (){
//...
}
Function cat (){
//...
}
Cat. prototype = new Animal (); // This method inherits from the constructor.
Cat. prototype = Animal. prototype; // This method does not inherit from the constructor.
// Another important thing to note is that you must maintain your prototype chain. New users will always forget this!
Cat. prototype. constructor = cat;

If we completely change the prototype attribute of the function (by allocating a new object), the reference to the original constructor is lost because the created object does not include the constructor attribute:

Copy codeThe Code is as follows:
Function (){}
A. prototype = {
X: 10
};
Var a = new ();
Alert (a. x); // 10
Alert (a. constructor === A); // false!

Let's take a look at the constructor explanation on MDN: prototype: Returns a reference to the Object function that created the instance's prototype. therefore, the prototype reference of the function must be manually restored:

Copy codeThe Code is as follows:
Function (){}
A. prototype = {
Constructor:,
X: 10
};
Var a = new ();
Alert (a. x); // 10
Alert (a. constructor === A); // true

However, submitting the prototype attribute does not affect the prototype of the created object (only when the prototype attribute of the constructor is changed). That is to say, only the newly created object has a new prototype, the created object is still referenced to the original prototype (this prototype cannot be modified again ).
Copy codeThe Code is as follows:
Function (){}
A. prototype. x = 10;
Var a = new ();
Alert (a. x); // 10
A. prototype = {
Constructor:,
X: 20
Y: 30
};
// Object a is a value obtained from the Prototype of crude oil through implicit [[prototype] reference
Alert (a. x); // 10
Alert (a. y) // undefined
Var B = new ();
// But the new object is the value obtained from the new prototype.
Alert (B. x); // 20
Alert (B. y) // 30

Therefore, "Dynamic Prototype modification will affect all objects to have a new prototype" is incorrect. The new prototype takes effect only for newly created objects after the prototype is modified. The main rule here is: the object prototype is created when the object is created, and cannot be modified to a new object after this. If it is still referenced to the same object, you can use the explicit prototype reference of the constructor. After an object is created, you can only add or modify the attributes of the prototype.

In the context of function execution, VO (variable object) cannot be directly accessed. In this case, the activation object plays the VO role. An active object is created when the context of the function is entered. It is initialized through the arguments attribute of the function. The value of the arguments attribute is an Arguments object:


Copy codeThe Code is as follows:
Function foo (x, y, z ){
// Number of declared function parameters arguments (x, y, z)
Alert (foo. length); // 3
// The number of actually passed parameters (only x, y)
Alert (arguments. length); // 2
// The callee parameter is the function itself
Alert (arguments. callee = foo); // true
}

When entering the execution context (before code execution), VO contains the following attributes: 1. All the parameters of the function (if we are in the context of function execution );

• All function declarations (FD );
• All variable declarations (var, VariableDeclaration );
Another typical example:

Copy codeThe Code is as follows:
Alert (x); // function
Var x = 10;
Alert (x); // 10
X = 20;
Function x (){};
Alert (x); // 20

According to the canonicalized function declaration, it is filled when the context is entered; when the context is entered, there is also a variable Declaration "x", as we mentioned above, the variable declaration follows the function declaration and formal parameter declaration in sequence, and enters the context stage. The variable declaration does not interfere with the existing function declaration of the same name or formal parameter declaration in VO. Compared with a simple attribute, a variable has a feature (attribute): {DontDelete}. This feature means that the delete operator cannot be used to directly delete the variable attribute.

Copy codeThe Code is as follows:
A = 10;
Alert (window. a); // 10
Alert (delete a); // true
Alert (window. a); // undefined
Var B = 20;
Alert (window. B); // 20
Alert (delete B); // false
Alert (window. B); // still 20. B is variable, not property!
Var a = 10; // a variable in the Global Context
(Function (){
Var B = 20; // The local variable in the function Context
})();
Alert (a); // 10
Alert (B); // The global variable "B" is not declared.

In the context of a function, this is provided by the caller and determined by the method of calling the function. If the left side of the brackets () is the reference type value, this is set to the base object of the reference type value ), in other cases (any other attribute that is different from the reference type), the value is null. However, the actual value of this is null, because when the value of this is null, its value is implicitly converted to a global object.

Copy codeThe Code is as follows:
(Function (){
Alert (this); // null => global
}) (); <SPAN style = "LINE-HEIGHT: 25.2px; FONT-FAMILY: Helvetica, Tahoma, Arial, sans-serif; FONT-SIZE: 14px "> </SPAN>

In this example, we have a function object, but it is not a reference type object (it is neither a identifier nor an attribute accessor). Correspondingly, this value is finally set as a global object.

Copy codeThe Code is as follows:
Var foo = {
Bar: function (){
Alert (this );
}
};
Foo. bar (); // Reference, OK => foo
(Foo. bar) (); // Reference, OK => foo
(Foo. bar = foo. bar) (); // global
(False | foo. bar) (); // global
(Foo. bar, foo. bar) (); // global

The problem lies in the following three calls. After a certain operation is applied, the value on the left of the call bracket is not of the reference type.

• The first example is obvious-the obvious reference type. The result is that this is the base object, that is, foo.

• In the second example, the group operator is not applicable. Think about the method mentioned above to obtain the true value of an object from the reference type, such as GetValue. Correspondingly, in the return of group operations, we still get a reference type. This is why this value is set as the base object again, that is, foo.

• In the third example, unlike the group operator, the value assignment operator calls the GetValue method. The returned result is a function object (but not a reference type), which means that this is set to null and the result is a global object.

• The fourth and fifth operators are the same-the comma operator and the logical operator (OR) Call the GetValue method. Correspondingly, we get the function without referencing it. And set it to global again.

As we know, local variables, internal functions, and form parameters are stored in the activation object of a given function.

Copy codeThe Code is as follows:
Function foo (){
Function bar (){
Alert (this); // global
}
Bar (); // the same as AO. bar ()
}

The activity object is always returned as this, and the value is null -- (that is, the AO. bar () of the pseudo code is equivalent to null. bar ()). Here we will go back to the example described above and set this as a global object.


Scope chain

The scope attribute of the function created by using the function constructor is always a unique global object.

An important exception involves functions created through function constructor.

Copy codeThe Code is as follows:
Var x = 10;
Function foo (){
Var y = 20;
Function barFD () {// function declaration
Alert (x );
Alert (y );
}
Var barFn = Function ('alert (x); alert (y );');
BarFD (); // 10, 20
BarFn (); // 10, "y" is not defined
}
Foo ();

Also:

Copy codeThe Code is as follows:
Var x = 10, y = 10;
With ({x: 20 }){
Var x = 30, y = 30;
// Here, x = 30 overwrites x = 20;
Alert (x); // 30
Alert (y); // 30
}
Alert (x); // 10
Alert (y); // 30

What happens when the context is entered? The identifiers "x" and "y" have been added to the variable object. In addition, make the following changes in the Code running phase:

• X = 10, y = 10;
• The object {x: 20} is added to the frontend of the scope;
• In with, a var declaration is encountered, and nothing is created, because when the context is entered, all variables have been parsed and added;
• In Step 2, only the variable "x" is modified. In fact, "x" in the object is resolved and added to the frontend of the scope chain. "x" is 20, changed to 30;
• There are also modifications to the variable object "y". After being parsed, its value also changes from 10 to 30;
• After the with declaration is complete, its specific objects are 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 the with is enhanced.
• In the last two alert statements, the "x" of the current variable object remains the same, and the "y" value is now equal to 30, which has changed in the with declaration runtime.
Function

Parentheses

Let's take a look at this question: 'Why must parentheses be used to enclose the function in the call immediately after the function is created? ', The answer is: the limit of expression sentences is like this.

According to the standard, an expression statement cannot start with a braces {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, if we define a function to be executed immediately, call it as follows immediately after it is created:

Copy codeThe Code is as follows:
Function (){
...
}();
// Even if there is a name
Function foo (){
...
}();

We use the function declaration. The two definitions mentioned above indicate that the interpreter will report errors during interpretation, but there may be multiple reasons. If it is defined in the Global Code (that is, the program level), the interpreter will regard it as a function declaration, because it starts with the function keyword. In the first example, we will get the SyntaxError error, because the function declaration has no name (we mentioned earlier that the function declaration must have a name ). In the second example, a function declaration named foo is created normally, but we still get a syntax error-the grouping operator error without any expressions. After the function declaration, it is indeed a grouping operator, rather than the parentheses used by a function call. So if we declare the following code:

Copy codeThe Code is as follows:
// "Foo" is a function declaration, which is created when the context is entered.
Alert (foo); // Function
Function foo (x ){
Alert (x );
} (1); // This is just a grouping operator, not a function call!
Foo (10); // This is a real function call. The result is 10.

The simplest way to create an expression is to use the grouping operator parentheses, which are always placed in the expression, so the interpreter will not be ambiguous during interpretation. In the code execution phase, this function will be created, executed immediately, and then automatically destroyed (if not referenced)

Copy codeThe Code is as follows:
(Function foo (x ){
Alert (x );
}) (1); // This is the call, not the grouping operator.

The above code is what we call in parentheses to enclose an expression and then call it through (1. NOTE: For the following function to be executed immediately, parentheses are not required because the function is already in the position of the expression, the parser knows that it processes the FE that should be created during the function execution phase, so that the function is called immediately after the function is created.

Copy codeThe Code is as follows:
Var foo = {
Bar: function (x ){
Return x % 2! = 0? 'Yes': 'no ';
} (1)
};
Alert (foo. bar); // 'yes'

As we can see, foo. bar is a string rather than a function. The function here is only used to initialize this attribute based on the condition parameter-it is created and called immediately.


1. Therefore, the complete answer to the question "Parentheses" is as follows:
2. When a function is not in the position of an expression, the grouping operator parentheses are required-that is, the function is manually converted to FE.
3. If the parser knows that it is processing FE, there is no need to use parentheses.
Free variables:

Copy codeThe Code is as follows:
Function testFn (){
Var localVar = 10; // For the innerFn function, localVar is a free variable.
Function innerFn (innerParam ){
Alert (innerParam + localVar );
}
Return innerFn;
}

Static scopes of closures:
 Copy codeThe Code is as follows:
Var z = 10;
Function foo (){
Alert (z );
}
Foo (); // 10-When static and dynamic scopes are used
(Function (){
Var z = 20;
Foo (); // 10-use static scope, 20-use dynamic scope
})();
// Use foo as a parameter.
(Function (funArg ){
Var z = 30;
FunArg (); // 10-static scope, 30-dynamic scope
}) (Foo );
 

Theory: because of the scope chain, all functions are closures (irrelevant to function types: anonymous functions, FE, NFE, and FD are closures ). From a practical perspective: The following functions are regarded as closures: * even if the context of the created function has been destroyed, it still exists (for example, internal functions are returned from the parent function)

* Free variables are referenced in the code.

Finally:
ECMAScript is an object-oriented language that supports prototype-based delegated inheritance.

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.