1. Review what you learned in the last section
1. Execution context classification: global execution context; Function execution context; Eval Eval Eval eval eval eval eval eval eval eval eval eval eval eval eval eval eval 3. In ES6, the difference between a lexical environment and a variable environment is that the former is used to hold function declarations and let and const declarations. The latter is used to hold variables declared by var. 4. In JavaScript, base data types are stored on the stack and reference types are stored in the heap. 5. Memory reclamation: It is difficult to determine when global variables are recycled. Local variables are recycled when used up, so avoid using global variables as much as possible. 6. Memory reclamation algorithm: reference counting (no longer used in modern browsers); Tag cleanup (which modern browsers mostly use). 7. Memory leak: Overflow occurs if unused memory is not freed -- Free memory: assign null, ##. The 'this' keyword is one of the most complex mechanisms in JavaScript. It is a special keyword that is automatically defined in the scope of all functions. But even experienced 'JavaScript' developers have a hard time figuring out what it points to. Execution context Classification: Global execution context; Function execution context; Eval Execution Context Which steps are involved in the creation of an execution context: 1. Binding this; Create a lexical environment. 3. Create a variable environmentCopy the code
2. Understanding of this mistake
2.1 Myth 1: This refers to itself
The first common misconception is that this refers to the function itself. ```js function foo(num) { console.log( "foo: " + num ); // Count the number of times foo is called this.count++; } foo.count = 0; var i; for (i=0; i<10; i++) { if (i > 5) { foo( i ); } } console.log(foo.count); Parsing: Following our normal logic, the for loop executes four times, and foo.count should print 4. But foo.count actually prints 0. Why? Because the above code actually creates a global count that is different from foo.count. If we want foo.count to output the expected 4, what changes should we make?Copy the code
2.2 Myth 2: This refers to the scope of a function
The second common misconception is that this refers to the scope of a function. ```js function foo() { var a = 2; this.bar(); } function bar() { console.log( this.a ); } foo(); // undefined: undefined: what is wrong with this code? First, the code attempts to reference the bar() function via this.bar(). If you want to reference the bar function, you can reference it directly. In addition, the developer who wrote this code is trying to use this to connect the lexical scopes of foo() and bar() so that bar() can access variable A in the scope of foo(). This is impossible. You can't use this to refer to something inside a lexical scope.Copy the code
2.3 What exactly is this?
The execution environment of the lexical scope is specified at code writing, whereas' this' is bound at run time. The binding of 'this' has nothing to do with location, but depends on how the function is called. When the function described in the previous section is called, it creates an execution context that contains the binding of 'this', the lexical context, and the variable context. The lexical context has two parts: the context record and the reference to the external environment. The environment record contains the actual location of function declarations and variable stores, while references to the external environment show the external lexical environment to which they can refer. ** 'this' is actually a binding that happens when the function is called, and what it points to depends entirely on where the function is called. 支那Copy the code
3. Understand this deeply
3.1 Call Location
Before you understand the binding process for 'this', you need to understand the call location: the call location is where a function is called in code (not declared). Only careful analysis of the call location can answer the question: What does this' this' refer to? In general, finding the calling location is looking for "where the function is called," but this is not as easy to do because some programming patterns can hide the actual calling location. The most important thing is to analyze the execution stack (also known as the call stack, as we discussed in the previous section), which has a LIFO (LIFO) structure for storing all execution contexts created during code execution. When JS code is first run, a global execution context is created and pushed into the current execution stack. Each time a function call occurs, the engine creates a new function execution context for that function and pushes it to the top of the current execution stack. According to the execution stack LIFO rule, when the top function runs, its corresponding execution context will Pop out of the execution stack, and the control of the context will be moved to the next execution context of the current execution stack). The call location we care about is in the previous call to the currently executing function. Js function baz() {// The current call stack is: baz // therefore, the current call location is global scope console.log("baz"); bar(); Function bar() {// The current call stack is baz -> bar // therefore, the current call position is in baz console.log("bar"); foo(); Function foo() {// The current call stack is baz -> bar -> foo // so the current call position is in bar console.log("foo"); } baz(); // <-- call location of baz notice how we parse out the real call location (from the call stack), since it determines the binding of 'this'.Copy the code
3.2 Binding Rules
3.2.1 Default Binding
```js function foo() { console.log( this.a ); } var a = 2; foo(); ``` ```js function foo() {"use strict" // When the function runs in strict mode, This is bound to undefined console.log(this.a); } var a = 2; foo(); //undefined * is the default rule that applies no other rules and is a stand-alone function call (called from a function reference without any modifiers). * When a function is running in strict mode, the default binding cannot be used for global objects. 'this' is bound to' undefined '. Only when a function is running in non-strict mode can the default binding be used for global objects.Copy the code
3.2.2 Implicit binding
Implicit binding: Another rule to consider is whether the calling location has a context object, or is owned or contained by an object, although this can be misleading. ```js function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; obj.foo(); In the above code, the calling position uses the 'obj' context to refer to the function. We can say that the 'obj' object 'owns' or' contains' the function when it is called, but strictly speaking the function does not belong to the 'obj' object. No matter what you call this pattern, when 'foo()' is called, its foothold does point to an 'obj' object. When a function references a context object, the implicit binding rule binds the 'this' in the function call to that context object. Because 'this' is bound to' obj 'when' foo() 'is called,' this.a 'and' obj. A 'are the same. ##### 3.2.2.1 Implicit Loss In some cases, implicitly bound functions will lose their bound objects, and the default rule will apply, namely binding 'this' to a global object (in non-strict mode) or' undefined '(in strict mode). ```js function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; var bar = obj.foo; // Function alias! var a = "oops, global"; // a is the global object property bar(); While 'bar' is a reference to 'obj.foo', it actually refers to the function 'foo' itself, so 'bar()' is actually a function call without any decoration, so the default binding is applied. The following chart helps us understand. ! [_20190417112206. PNG] (http://172.16.14.82:9000/ibed/2019/04/16/47f3d46928e64c95add95e256ee0fa3a.png), there is a kind of situation, on the reference: ```js function foo() { console.log( this.a ); } function doFoo(fn) {// fn refers to foo fn(); // <-- call location! } var obj = { a: 2, foo: foo }; var a = "oops, global"; // a is the global object's property doFoo(obj.foo); // Oops, global 'is an implicit assignment, so we pass in a function that is implicitly assigned, so the result is the same as in the previous example.Copy the code
3.2.3 Displaying binding
As we have just seen, when analyzing implicit binding, we must bind 'this' indirectly (implicitly) to an object by including an attribute that points to a function and by referring to the function indirectly through this attribute. So what if we want to force a function call on an object instead of including a function reference inside the object? Here we introduce two common js methods: 'apply(...). ` and ` call (...). * Apply syntax: func.apply(thisArg, [argsArray]) 'thisArg' -- optional. The 'this' value used when the' func 'function is run. Note that ** 'this' may not be the actual value seen by this method: if the function is in non-strict mode, specifying' null 'or' undefined 'is automatically replaced with pointing to a global object, and the original value is wrapped **. 'argsArray' -- optional. An array or array-like object whose array elements are passed as individual arguments to the 'func' function. If the value of this parameter is' null 'or' undefined ', no arguments need to be passed in. Array-like objects can be used starting with ECMAScript 5. * Call syntax: fun.call(thisArg, arg1, arg2...) 'thisArg' -- the value of 'this' specified when fun is run. Note that the specified 'this' value is not necessarily the true' this' value when the function is executed. If the function is run in non-strict mode, This values specified as null and undefined will automatically point to global objects (the 'window' object in browsers), while this values of raw values (numbers, strings, bools) will point to the auto-wrapped object of that raw value. `arg1, arg2, ... '-- a list of specified arguments. * Encapsulation: Primitive values do not have properties and methods such as.length and.toString(). JavaScript will automatically box or wrap a wrapped object around the value of the primitive type. ```js var a = "abc"; a.length; // 3 a.toUpperCase(); Var a = new String("ABC"); var a = new String("ABC"); var b = new Number( 42 ); var c = new Boolean( true ); a.valueOf(); // "abc" b.valueOf(); // 42 c.valueOf(); Implicit unpacking occurs where a value of the primitive type in the encapsulated object is needed. ```js function foo (a, b) { console.log(this.a); Console. log(a) console.log(b)} ``` ` The difference between apply and call: 'apply' accepts a list of multiple arguments, while 'call' accepts a list of several arguments. ```js let obj = { a: 'Hello' }; foo.call(obj, 'Tom', 'Jerry'); foo.apply(obj, ['Tom', 'Jerry']); Use 'call' and 'apply' to force 'this' to be bound to the object you want. However, the problem of 'this' loss mentioned above still cannot be solved. There are two ways to solve this problem. # # # # # 3.2.3.1 hard binding ` ` ` js function foo () {the console. The log (enclosing a); } var obj = { a:2 }; var bar = function() { foo.call( obj ); }; bar(); // 2 setTimeout( bar, 100 ); // 2 // A hard-bound bar cannot change its this bar.call(window); // 2 we create function 'bar()' and manually call 'foo.call(obj)' inside it, thus forcing foo's 'this' to be bound to' obj '. No matter how function 'bar' is later called, it will always manually call 'foo' on 'obj'. This binding is explicitly forced and is therefore called hard binding. A typical case of hard binding is to create a wrapped function that passes in all the arguments and returns all the values it received: js function foo(something) {console.log(this.a, something); return this.a + something; } var obj = { a:2 }; var bar = function() { return foo.apply( obj, arguments ); }; var b = bar( 3 ); // 2 3 console.log( b ); // js function foo(something) {console.log(this.a, something); return this.a + something; Function bind(fn, obj) {return function() {return fn.apply(obj, arguments); }; } var obj = { a:2 }; var bar = bind( foo, obj ); var b = bar( 3 ); // 2 3 console.log( b ); // the function.prototype. bind() method is called function.prototype. bind(). A quick review of the following 'bind()' methods: syntax: Bind (thisArg[, [arg1[, arg2[,...]]]) 'thisArg' -- the value passed to the target function as the 'this' argument when calling the binding function. If the' new 'operator is used to construct the binding function, When using 'bind' to create a function in 'setTimeout' (provided as a callback), any original values passed as' thisArg 'will be converted to' object '. If the argument list of 'bind' is empty, 'arg1, arg2,...' -- arguments that are pre-added to the argument list of the binding function when the target function is called. 'bind' returns a function that binds the context, Js function foo(something) {console.log(this.a, something ); return this.a + something; } var obj = { a:2 }; var bar = foo.bind( obj ); var b = bar( 3 ); // 2 3 Console.log (b); // 5 ``` `bind(..) 'returns a new hard-coded function that sets the argument to the context of' this' and calls the original function.Copy the code
3.2.3.2 Context of API calls
Many functions in third-party libraries, as well as many new built-in functions in the JavaScript language and host environments, provide an optional argument, often referred to as a "context," which serves the same function as' bind(..) '. Make sure your callback uses the specified 'this' as well. ```js function foo(el) { console.log( el, this.id ); } var obj = { id: "awesome" }; / / calls foo (..) Bind this to obj [1, 2, 3]. ForEach (foo, obj); // 1 awesome 2 awesome 3 awesome ```Copy the code
3.2.4 new binding
In JavaScript Objects and Prototypes, we talked about what happens when a constructor is called through new: 1. Create (or construct) a brand new object. 2. Create its constructor. 3. The new object will be connected by the implementation [[prototype]]. 4. The new object will be bound to the function call's 'this'. 5. If the function returns no other object, the function call in the 'new' expression automatically returns the new object. Word-wrap: break-word! Important; "> < p style =" max-width: 100%; ```js function create() { let obj = new Object(); let Con = [].shift.call(arguments); obj.__proto__ = Con.protoType; let ret = Con.apply(obj,arguments); return typeof ret === 'object'? ret : obj; } function Person(name) {this.name = name;} function Person(name) {this.name = name; return 'new person'; } let person = new Foo('Lucy'); person.name; // Lucy let person = create(Person, 'Lucy'); person.name; Js function foo(a) {this.a = a; } var bar = new foo(2); console.log( bar.a ); // 2 'uses' new' to call 'foo' (..). ', we'll construct a new object and bind it to 'foo(..). On 'this' in the' this' call. 'new' is the last method that can affect the behavior of the 'this' binding when a function is called. This is called the' new 'binding.Copy the code
4. Priority
We have given a total of 4 rules binding this above, so we need to consider which of these four rules has a higher priority? Priority comparison: New Binding > Explicit Binding > Implicit Binding > Default binding 1. Is the function called in new (new binding)? If so, this binds to the newly created object. Var bar = new foo() 2. Is the function called by call, apply, or hard binding? If so, this binds to the specified object. Var bar = foo.call(obj2) 3. Is the function called in a context object (implicitly bound)? If so, this binds to the upper context object. Var bar = obj1.foo() 4. If neither of them exists, use the default binding. If in strict mode, it is bound to undefined, otherwise it is bound to global objects. var bar = foo() ``` <! > < span style = "max-width: 100%; clear: both; min-height: 1em; Js function foo(something) {console.log(this.a, something); return this.a + something; } var obj1 = { a: 2; foo: foo }; var obj2 = { a: 3; foo: foo }; var a = obj1.foo() var bar = foo.bind( obj2 ); var b = bar( 3 ); // 2 3 console.log( b ); / / 5 ` ` ` -- -- >Copy the code
5. Binding exceptions
5.1 Ignored this
If 'null' or 'undefined' is passed as the first parameter, then 'this' will be bound to the global variable' window 'in non-strict mode. Null is passed as an argument when expanding an element in an array or when a function is currified. ```js function foo(a,b) { console.log( "a:" + a + ", b:" + b ); } foo.apply( null, [2, 3] ); // a:2, b:3 Var bar = foo.bind(null, 2); bar( 3 ); // a:2, b:3 however, always using 'null' to ignore the 'this' binding can have some side effects. If a function does use 'this' (such as a function in a third-party library), the default binding rule binds' this' to a global object (which in browsers is a window), which can have unpredictable consequences (such as modifying the global object). > We generally recommend using 'object.create (null)' instead of using 'null' directly, because any use of 'this' is restricted to the empty Object and has no effect on the global Object.Copy the code
5.2 Indirect Reference
```js function foo() { console.log( this.a ); } var a = 2; var o = { a: 3, foo: foo }; var p = { a: 4 }; o.foo(); // 3 (p.foo = o.foo)(); // the return value of the assignment expression p.foo = o.foo is a reference to the target function, so the call location is foo() instead of p.foo() or o.foo(). As we said earlier, the default binding is applied here. Note: For the default binding, it is not the calling position of the 'this' binding object that determines whether it is in strict mode, but the function body. If the function body is in strict mode, 'this' will be bound to' undefined ', otherwise 'this' will be bound to the global object.Copy the code
5.3 soft binding
We mentioned hard binding above, so why soft binding here? The main disadvantage of hard binding is that once you specify 'this' with hard binding, you can no longer use implicit binding to change the direction of' this', greatly reducing flexibility. In this case, soft binding is proposed. Soft binding: By specifying a global object and a value other than 'undefined' for the default binding, you can achieve the same effect as hard binding, while retaining the ability to modify 'this' implicitly or explicitly. ```js function foo() { console.log("name: " + this.name); } var obj = { name: "obj" }, obj2 = { name: "obj2" }, obj3 = { name: "obj3" }; var fooOBJ = foo.softBind( obj ); fooOBJ(); // name: obj obj2.foo = foo.softBind(obj); obj2.foo(); // name: obj2 <---- fooOBJ.call( obj3 ); // obj3 <---- setTimeout( obj2.foo, 10 ); // name: obj <---- Soft binding is appliedCopy the code
Arrow function
Arrow functions do not apply to the above binding rules. The 'this' of arrow functions is scoped lexical and determines' this' according to the outer scope. However, if the outer function is not an arrow function, the above four rules can still be applied. In some cases, arrow functions are also "dynamically bound". Js function foo() {return (a) => {//this inherits from foo().console.log (this.a); }; } var obj1 = { a:2 }; var obj2 = { a:3 }; var bar = foo.call( obj1 ); bar.call( obj2 ); Result: 2 <! --> <! Give console.log output values in sequence: --> <! --```js--> <! --var num = 1; -- > <! --var myObject = {--> <! -- num: 2,--> <! -- add: function() {--> <! -- this.num = 3; -- > <! -- (function() {--> <! -- console.log(this.num); -- > <! -- this.num = 4; -- > <! -}) (); -- > <! -- console.log(this.num); -- > <! -} -- > <! -- sub: function() {--> <! -- console.log(this.num); -- > <! -} -- > <! -} -- > <! --myObject.add(); -- > <! --console.log(myObject.num); -- > <! --console.log(num); -- > <! --var sub = myObject.sub; -- > <! --sub(); -- > <! - ` ` ` -- > <! -- Look at the answer: --> <! --```js--> <! --var num = 1; -- > <! --var myObject = {--> <! -- num: 2,--> <! -- add: function() {--> this.num = 3; // myObject.add() is called implicitly, so this refers to the calling context object, myObject.num=3. <! -- (function() {--> console.log(this.num); Num = 4; // This is the global object window.this. num = 4; // window.num=4 <! -}) (); --> console.log(this.num); // MyObject.num = 3. <! -} -- > <! -- sub: function() {--> console.log(this.num); Num = 4. <! -} -- > <! -} -- > <! --myObject.add(); -- > <! --console.log(myObject.num); --> console.log(num); Num = 4. <! --var sub = myObject.sub; --> sub(); // This is where the function is actually called, without any modifiers, so the default rules apply. - ` ` ` - > reference: Js You Don't Know -- Volume 1 --Kyle Simpson, MDN Web Docs --[mdn](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function)Copy the code