Home  >  Article  >  Web Front-end  >  A brief discussion on the analysis of language features of JavaScript_javascript skills

A brief discussion on the analysis of language features of JavaScript_javascript skills

WBOY
WBOYOriginal
2016-05-16 17:37:32955browse

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:

Copy code The code is as follows:

[javascript] view plaincopyprint?
var f = function foo(){
return typeof foo; // foo is valid within the internal scope
};
// foo is invisible when used externally
typeof foo; // "undefined"
f(); // "function"
var f = function foo(){
return typeof foo; // foo is valid in the inner scope
};
// foo Invisible when used externally
typeof foo; // "undefined"
f(); // "function"

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.

Copy code The code is as follows:

[javascript] view plaincopyprint?
// This Is a JSON string
var foo = '{ "prop": "val" }';
// This is an object literal
var bar = { "prop": "val" };
// This is a JSON string
var foo = '{ "prop": "val" }';
// This is an object literal
var bar = { "prop": "val" };

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

Copy code The code is as follows:

function Animal (){
// .. .
}
function cat (){
// ...
}
cat.prototype = new Animal();//This method will inherit what is in the constructor.
cat.prototype = Animal.prototype;//This method will not inherit the constructor.
//Another important detail to note is that you must maintain your own prototype chain. Newbies will always forget this!
cat.prototype.constructor = cat;

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:

Copy code The code is as follows:

function A() {}
A.prototype = {
x: 10
};
var a = new A();
alert(a.x); // 10
alert(a.constructor === A); / / false!

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:

Copy code The code is as follows:

function A() {}
A.prototype = {
constructor: A,
x: 10
};
var a = new A();
alert(a.x); // 10
alert(a.constructor === A); // true

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).

Copy code The code is as follows:

function A() {}
A.prototype .x = 10;
var a = new A();
alert(a.x); // 10
A.prototype = {
constructor: A,
x: 20
y: 30
};
//Object a is the value obtained from the prototype of crude oil through the implicit [[Prototype]] reference
alert(a.x); // 10
alert (a.y) // undefined
var b = new A();
// But the new object is the value obtained from the new prototype
alert(b.x); // 20
alert(b.y) // 30

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:


Copy code The code is as follows:

function foo(x, y, z) {
// Number of declared function parameters arguments (x, y, z)
alert(foo.length); // 3
// Number of parameters actually passed in (only x, y)
alert(arguments.length); // 2
// The callee of the parameter is the function itself
alert(arguments.callee === foo); // true
}

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:

Copy code The code is as follows:

alert(x); // function
var x = 10;
alert(x); // 10
x = 20;
function x() {};
alert(x); // 20

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.

Copy code The 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; // Variable in global context
(function () {
var b = 20; // Local variable in function context
} )();
alert(a); // 10
alert(b); // Global variable "b" is not declared.

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.

Copy code The code is as follows:

(function () {
alert(this); // null => global
})();

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.

Copy code The 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 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.

Copy code The code is as follows:

function foo() {
function bar() {
alert(this); // global
}
bar(); // the same as AO.bar()
}

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.

Copy code The 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 code The code is as follows:

var x = 10, y = 10;
with ({x: 20}) {
var x = 30, y = 30;
//x = 30 here covers x = 20;
alert(x); // 30
alert(y); // 30
}
alert(x); // 10
alert(y); // 30

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:

Copy code The code is as follows:

function () {
...
}();
// Even if there is a name
function foo() {
...
}();

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:

Copy code The code is as follows:

// "foo" is a function declaration, after entering Create
alert(foo); // Function
function foo(x) {
alert(x);
}(1); // This is just a grouping operator, not Function call!
foo(10); // This is a real function call, the result is 10

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)

Copy code The code is as follows:

(function foo(x) {
alert( x);
})(1); // This is a call, not a grouping operator

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.

Copy code The code is as follows:

var foo = {
bar: function (x ) {
                                                                            . >

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:

Copy code The 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 scope of closure:

Copy code The code is as follows:

var z = 10;
function foo() {
alert(z);
}
foo(); // 10 – When using static and dynamic scopes
(function () {
var z = 20;
foo(); // 10 - use static scope, 20 - use dynamic scope
})();
// When foo is used as a parameter, Same
(function (funArg) {
var z = 30;
funArg(); // 10 – static scope, 30 – dynamic scope
})(foo);

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 code

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

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn