- The first part Scope and closure
- The second part this And object prototypes
I was recommended by my friends before 《 You don't know JavaScript》 This series of books . The upper, middle and lower three books are not thick , The content is also relatively independent . I was supposed to finish reading the first volume and the second volume in a month , But always because of their own laziness to read a month to read the first volume intermittently . I have to say that just reading the first volume is very rewarding for me , The following is the reading notes of the first volume , It's not a document or a tutorial , Just for your own learning record , You are welcome to point out the wrong understanding and opinions of the big guys passing by .
The first part Scope and closure
The first 1 Chapter What is the scope
1.1 Compiler principle
First , I also study JavaScript In limine , Find the information and say JavaScript It's a door “ interpreted ” Language . But in fact JavaScript It's a compiled language .
In traditional compiler languages , Before a piece of source code is executed, it goes through an operation called compilation , The compilation is as follows 3 A process .
- participle / Lexical analysis (Tokenizing/Lexing)
This process breaks down the programming language string into meaningful blocks of code , These blocks of code are called lexical units (token)
var a = 2;
// It will be broken down into var、a、=、2、; These are all lexical units
// Whether a space belongs to this unit depends on whether it makes sense ,
// there var a = 2; None of the spaces in is meaningful
- analysis / Syntax analysis (Parsing)
A stream of lexical units composed of many lexical units ( Array ) Convert to a tree structure , It's called abstract syntax tree (AbstractSyntaxTree,AST)
var a = 2;
// This sentence is transformed into a tree structure called VariableDeclaration
- Code generation
Transform the syntax tree into an executable code process .
Other languages are compiled before they are built , and JavaScript This compilation is also performed before execution 3 The part
1.2 Understand the scope
Yes var a = 2; When dealing with , The specific compiler works like this .
//1 encounter var a The compiler will query a collection in the current scope whether there is a This variable ,
// If you have, go ahead with 2 Step compiling action ,
// If not, the current scope will be required to declare a new a Variable
//2 encounter a = 2 The compiler generates runtime code for this statement , For runtime use .
// At this time, the compiler should express in the generated code a=2 That's what it means , So when generating code ,
// Need one a Variable , First find out whether the set in the current scope contains this variable ,
// If not, go up to the next floor . Until we find it , No, it's a mistake .
Note here that in step 2 in , The compiler will look for the scope set, and there will be 2 Different ways to look up , One is LHS, One is RHS. That is, left query and right query . This and I are learning C++ When it's middle left and right , I feel very familiar with . That is, through the most primitive “=” To understand , On the left is filled , On the right is to fill .
var a = 2;// Here, when the compiler generates code , Will go to the current scope set to find a Variable , Then it's assigned to 2.
// You can think of it as finding this piece called a Space , And fill it in 2 This data ,
// So here's the left query , That is to find the filled a Space
console.log(a)// Here, when the compiler generates code , Will go to the current scope set to find a Variable , Then print it out .
// You can think of it as finding this called a The value in the variable of , And then use this value ,
// So here's the right query , That is to find and fill ( Or take it out and use it ) Of a The value of space itself !!!
1.3 Scope nesting
In fact, this part of the book is about the scope chain , That is to say var a = 2; When dealing with , In the second step of the specific compiler work, one is needed a Variable , First find out whether the set in the current scope contains this variable , If not, go up to the next floor . Until we find it , Until there is no error at the top . And that's all the way up, down the scope chain .
var b = 3
function foo(a){
console.log(a+b)
}
foo(2)//4
// there function The interior is its own functional scope ,function Outside is the global scope .
//function Internal scopes don't have b Variable , Why can we still work specifically ?
// Because of function There is no , So go to the next level , And then there's... In the next level b, You can use
// This mechanism is scope nesting , Or scope chain .
// I mean , Child scopes can use parent scopes , But the parent scope cannot use the child scope in reverse .
// Of course, the father here 、 The subscope is for individuals to understand , I said , It's not a term .
1.5 abnormal
The first is when the search is successful along the scope chain , But we also said , If you can't find it, you will report an error . Here we look for 2 Medium condition . You can't find it naturally , Error reporting is not the same .
Here is a little verification of the left query in the book .
a = 2// Nothing here var Statement . however a=2 It's a left search , So the left query enthusiastically creates an empty a Variable space .
console.log(a)// The right search result is 2
"use strict"
a = 2// sorry , This left query cannot help generate an empty a Variable space ,
// This statement alone will fail because of the left query , newspaper ReferenceError
console.log(a)// Right search , Definitely fail , This sentence is also a failure report ReferenceError,
// But the first sentence is wrong , It doesn't even work .
The first 2 Chapter Lexical scope
2.1 Lexical stage
First of all, lexical scope is when you write code , The position of a written variable or block scope is a lexical scope . And this lexical analysis ( This is also the previous split statement var a = 2; by var、a、=、2、;), The scope is the same as when you write it . For example, the following code .
var a = 3;// This line is globally scoped
function foo(a) {
// Inside is foo The block scope formed by a function
// Write so the following b,bar(), And my own a. It's all in this scope
// So after the analysis, the relationship is still satisfied
var b = a * 2;// there a yes foo Inside the function , It's not outside var a = 3; Inside a
function bar(c) {
// Inside is bar The block scope formed by a function
// So one's own c It belongs here
console.log(a,b,c);
}
bar(b * 3);
}
foo(2);//2,4,12
Therefore, lexical scope mainly reflects 2 spot :
- One is to search for variables layer by layer by layer by scope , In this case bar The use of a,b,c From the next level foo.
- Two is , When a child scope has the same identifier as the parent scope ( It's the variable name 、 Function name ) When , Children will cover ( If you know method rewriting , In this case, the subclass rewrites the parent method ), This is called the shadowing effect . For example, in foo Scope 、 And in the child scope a When , All are foo Function a, instead of foo In the parent scope of the scope var a = 3; Medium a. Of course , When bar There is a When ,bar Use in a When , You'll use yourself a, And coverage foo(a) Of a, And the overall var a = 3 Of a
2.2 Deceptive vocabulary
First of all to remember , Use less deceptive words , Cheating on lexical scopes can lead to performance degradation . Use eval And with Keywords can do this . I'll just write here eval
First eval() To accept a string of strings , And replace the contents of the string to the calling position , A bit abstract , Please look at the code. :
function foo(str,a) {
// Here is foo The lexical scope of formation
// First pretend eval(str) non-existent
// There is only a And str It's your own. ,b It's outside
// So call foo("var b = 3;",1); Should be 1,2 Result
// Let go of comments eval(str)
// Output is 1,3
// because eval("var b = 3;") It's the same as in this line of business eval Replace the position with
//var b = 3;
// therefore var b = 3 Medium b Shield the outside b
//eval(str);
console.log(a,b);
}
var b =2;
foo("var b = 3;",1);//1,3
The first 3 Chapter Function scope and block scope
3.1 Scope in function
- Function scope : All variables belonging to this function can be used and reused within the scope of the entire function ( In fact, you can also use... In nested scopes ) This design can make full use of JavaScript Variable can change the value type as needed “ dynamic ” characteristic .
3.2 Hidden internal implementation
- Minimum exposure principle : In software design , It should be minimal exposure to the least content , And hide everything else .
- stay JavaScript Function scope in can achieve the effect of hidden code
function doSomething(a) {
b = a + doSomethingElse(a * 2);
console.log(b * 3);
}
function doSomethingElse(a) {
return a - 1;
}
var b;
doSomething(2);//15
Obviously, we can still access this and the time b as well as doSomethingElse() function , But as far as the code is concerned ,b as well as doSomethingElse() Just to give doSomething() Use . Therefore, we should not allow external access to these two identifiers . So it should be hidden
function doSomething(a) {
function doSomethingElse(a) {
return a - 1;
}
var b;
b = a + doSomethingElse(a * 2);
console.log(b * 3);
}
doSomething(2);//15
3.3 Function scope
Although the previous use of function wrapped code blocks to achieve the hidden meaning , But in some cases, there are still some shortcomings . One is to wrap the hidden function name and pollute the global variables , Then the name of the calling function that must be displayed . But fortunately, we can use the immediate execution function to solve this problem .
(function foo() {
var a = 3;
console.log(a);
})();
console.log(a);
// Here you can make a function an expression , Instead of a function declaration
// There's no such thing as foo Let it out and pollute the whole situation , Because he's not a statement
// And here's the last one (), Means to call immediately , So there's no need to display the use of identifier calls
// Of course, put the last () The effect of putting it in is the same , It's just that the writing style is different . as follows
(function foo() {
var a = 3;
console.log(a);
}());
console.log(a);
- Then it's a function expression ?
Good question
distinguish : The method in the book is very simple , It's about looking at function Where the keyword appears in the declaration ( It's not just a line of code , It's the position in the whole statement ). If function It's the first word in the statement , So it's a function declaration , Otherwise, it is a function expression .
In the above code (function foo(){…})() It's not function start , This is the expression , and foo The identifier is blocked in foo(){…} in … Part of , So there's no pollution of global variables
- Anonymity and anonymity
An anonymous function is a function without a name
setTimeout(function(){
console.log("I waited 1 second");
},1000);
In this part of the code fragment seTimeout in function() There's no name . So it's an anonymous function .
- Be careful : Only then can function expressions have this kind of anonymous function , Function expression has no function name . Look at the previous code , This is a function expression .
3.4 Block scope
Now we've learned the lexical scope 、 Function scope and some small knowledge points . Now learn the new scope 、 Block scope .
As I said before , Using function scope can hide a piece of code , And hiding means isolation . Isolate a piece of code into a function , Make it untouchable to the outside world . But we can't solve this problem by using outsourcing functions .
// This line of code is just for verification () Medium var i, as well as {} Medium a, Finally, these two identifiers can be accessed externally
for(var i = 0; i < 10; i++){
console.log("for It calls i",i);
var a = 5;
}
console.log("for Call out for Inside a",a); //for Call out for Inside a 5
console.log("for outside for Inside i",i);//for outside for Inside i 10
The following is the use of function wrapping
(function(){
for(var i = 0; i < 10; i++){
console.log("for It calls i",i);
var a = 5;
}
}())
console.log("for Call out for Inside a",a);//VM22:7 Uncaught ReferenceError: a is not defined
console.log("for Call out i",i);//Uncaught ReferenceError: i is not defined
It's done with the blockade , But it's not easy , So the developers are JavaScript Provides block scope . I think it's the same function as function scope , Block the code block in its {} in .
- let
let Declared variables , Is bound to the current scope .
for(let i = 0; i < 10; i++){
console.log("for It calls i",i);
var a = 5;
}
console.log("for outside for Inside i",i);//Uncaught ReferenceError: i is not defined
Congratulations ,i It's bound to for Inside the body , Is it more convenient .
Be careful let i, It's not just about putting i Bound to for Cyclic {} in , To be exact, it's bound to every iteration , This is very important . I'll talk about it again later in the closure . meanwhile let Declared identifiers are not promoted , This will be explained in the section on promotion later
-
const
const Declared variables , Is bound to the current scope , And the value of this variable is fixed , No more changes -
try/cath
I didn't think! , Every one of them cath It's all a branch , Unbelievable words , You can give it a try
The first 4 Chapter promote
First come to the conclusion that :
- Only the statement itself will be promoted , And assignment or other running logic will stay in place . If it's to improve the order of execution of the changed code , Can cause serious damage
- Declaration includes variable declaration and function declaration
- Each scope is promoted
- When functions and variables are raised , Functions take precedence . Because functions are first-class citizens
- let as well as const Declared identifiers are not promoted
foo();//1
var foo;
function foo() {
console.log(1);
}
foo = function () {
console.log(2);
}
The above code will be understood by the engine as follows :
function foo() {
console.log(1);
}
foo();//1
foo = function () {
console.log(2);
}
foo();//2
So functions are promoted first .
The first 5 Chapter Scope and closure
5.1 summary
I love opening , Just sum up .
Closure produces 2 In this case
- When a function is an argument to another function
- The function returns... As a return value
function foo() {
var a = 2;
function bar() {
console.log(a);
}
return bar;
}
var baz = foo();
baz();//2 friend , This is the closure effect
5.2 Loops and closures
To illustrate closure ,for Loop is a common example
for ( i = 1; i <= 5; i++) {
setTimeout(function timer(){
console.log(i);
}, i*1000);
}
When this code is run again, it will output once per second 5 Time 6.
The callback is called after the end of the loop ( Please check macro task 、 Micro task related knowledge points ), Instead of calling every iteration . So finally called i, however i It's public , And the value is determined by the last loop 6. So the result is 5 Time 6
How to get a real-time version for each iteration i, Even if it is the last iteration of the loop and then call the timing function , But every timing function calls its own version , Instead of calling the last public 6 Well ?
That's every iteration of the loop , We bind one for each iteration i. As shown below , We use let Let every one i All are bound by internal iteration .
for(let i = 1; i <= 5; i++){
setTimeout(function timer(){
console.log(i);
},i*1000);
}
5.3 modular
stay js Modules in are also closely related to closures .
modular :
- There has to be an external closed function , The function must be called once
- A closed function must return at least one inner function
- Using immediate execution functions works wonders
var foo = (function(){
var something = "cool";
var another = [1,2,3];
function doSomething() {
console.log(something);
}
function doAnother() {
console.log(another.join("!"));
}
return {
doSomething,
doAnother
}
})();
foo.doSomething();//cool
foo.doAnother();//1!2!3
The second part this And object prototypes
The first 1 Chapter About this
The first 2 Chapter this Comprehensive analysis
The first 3 Chapter object
The first 4 Chapter Mix objects “ class ”
The first 5 Chapter Prototype
The first 6 Chapter Act of commission
To be continued , Finish the second part next Saturday