this of JS points to the problem
This keyword is one of the most complex knowledge points in javascript. It is a special keyword, which is automatically defined in the scope of all functions. It is often used when writing javascript, but do you really understand this? As a qualified coder, he must not only recite the formula, but also understand the implementation logic. When learning this a long time ago, I made some small summaries and wrote some code to test constantly. I hope these study notes can help you.
this point classification
1.1 default binding
The default state is unbound, which is often used in independent functions.
function test(){ console.log(this.a); } var a = 1111; test(); //1111
Analysis output:
There is no object calling test() in front of it. This writing method applies the default binding of this. This points to the global object (in non strict mode), so 1111 is output
extend
In the non strict mode, the test() function will be mounted on the window. this in all functions points to the global object window.
In strict mode: this keyword is prohibited from pointing to the global object, this keyword points to the undefined, and the undefined has no global object. An error is thrown
1.2 implicit binding
The call of a function is triggered on an object, and there is a context object at the call location. The typical form is XXX.fun();
function test(){ console.log(this.a); } var obj = { a:1111, test:test } obj.test(); //1111
Analysis output results
The test() function is declared externally and does not strictly belong to obj. However, when calling test(), the calling location will use the obj context to reference the function. Implicit binding will bind this in the function call, that is, this in test(), to this context object (obj).
- Always remember one sentence: this always points to the object that was invoked at last. Only the last layer in the object property chain affects the location of the call
function test(){ console.log(this.a); } var obj1 = { a:1111, test:test } var obj2 = { a:2222, obj1:obj1 } obj2.obj1.test(); //1111,this points to obj1 to which it was last bound
Note that implicit loss often occurs in implicit binding
Q: What is implicit loss?
A: The bound function is missing the bound object.
attention: parameter passing is actually an implicit assignment
function fn(){ console.log(this.a); } var a = 'hello world'; var obj = { a:'obj', fn:fn } var demo = obj.fn; demo(); //The console finally prints hello world
Analysis output results
The demo directly points to the reference of fn, and the call has nothing to do with obj. The demo is bound with the reference of fn function, so the demo is just a function call. The default binding is applied and the global object is bound. So print out hello world.
- Confusing knowledge points: XXX.fn(); If there is nothing before fn(), it is not an implicit binding.
In addition to the above loss, implicit binding loss often occurs in callback functions (event callback is also one of them)
function test(){ console.log(this.a); } function gn(fn){ fn(); } var obj = { a:1111, test:test } var a = 'I am a global object' gn(obj.test); //I am a global object
Once again, parameter passing is also an invisible assignment
- Special case: timer setTimeout
function test(){ console.log(this.a); } var a = 'hello world'; var obj = { a:'obj', test:test } setTimeout(obj.test,0); //hello world
Output result analysis
The first parameter of setTimeout is the incoming callback function. obj.test is bound as a function, which is equivalent to
function setTimeout(test,delay){//delay execution in milliseconds test();//obj.test }
1.3 explicit binding
Directly specify this binding object with the help of apply,call,bind and other methods. The first parameter of call, apply and bind is the object pointed to by this of the corresponding function.
Q: What's the difference between apply and call.bind?
A: The functions of apply and call are the same, and the methods of passing parameters are different. The corresponding functions will be executed, but bind is different. It will not be executed and needs to be called manually.
//apply binding function test(){ console.log(this.a); } var obj = { a:1111, } test.apply(obj);//hello world
//call binding function test(){ console.log(this.a); } var obj = { a:1111, } test.call(obj);//hello world
Does explicit binding prevent binding loss? Of course not
- Explicit binding also faces the problem of binding loss
function sayHi(){ console.log('hello',this.name); } var obj = { name:'Gabrielle', sayHi:sayHi } var name = 'Gaby'; var Hi = function(fn){ fn(); } Hi.call(obj,obj.sayHi); //hello,Gaby
Output result analysis
When fn is executed, it is equivalent to directly calling the sayHi method (obj.sayHi has been assigned to fn, and the implicit binding has been lost). The value of this is not specified, and the default binding is corresponding. So the output is hello Gaby.
Q: How to solve the problem of binding loss?
A: Hard bind this to fn.
function sayHi(){ console.log('hello',this.name); } var obj = { name:'Gabrielle', sayHi:sayHi } var name = 'Gaby'; var Hi = function(fn){ fn.call(this); } Hi.call(obj,obj.sayHi); //hello,Gabrielle
Output result analysis
Because obj is bound to this in the Hi function, fn binds this function to the sayHi function.
It can also be rewritten with bind, which is classified as hard binding.
function sayHi(){ console.log('hello',this.name); } var obj = { name:'Gabrielle', sayHi:sayHi } var name = 'Gaby'; var Hi = sayHi.bind(obj); Hi.call(obj,obj.sayHi); //hello,Gabrielle
- Binding exception
Apply binding rules: null and undefined are passed into call, apply and bind as binding objects. These values are often ignored
var obj = { name:'Gabrielle' } var name = 'Gaby'; function Hi() { console.log(this.name); } Hi.call(null); //Gaby
1.4 new binding
js has no class. Simulate the class through the constructor and call the function with new. The following operations will be performed automatically
Create an object. The object is connected by [[Prototype]]. The new object will be bound to this of the function call. If the function does not return other objects, the new object will be returned. Otherwise, the object returned by the constructor will be returned.
- Handwritten new
//1. Create an empty object function _new(fn,...args){ //2. Of this object__ proto__ The prototype object that points to fn this constructor var obj = Object.create(fn.prototype); //3. Change this point var res = fn.apply(obj,args); // 4. If the result returned by the constructor is a reference data type, the result after running will be returned; otherwise, the newly created obj will be returned if ((res!==null && typeof res == "object") || typeof res == "function") { return res; } return obj; }
- new bind this
function person(name){ this.name = name; } var per = new person('Gaby'); console.log(per.name); //Gaby //per has been bound to this called by person
Insert a small clip
When writing the above code, I forgot to pass in the parameter to person(), resulting in the console printing undefined. Then I was thinking about a question, why can I have normal output only by passing in parameters to person(). What is the logic behind this? Here's a reminder. function person() is a constructor. this.name wants to get the name, but my name is not passed in. The name I want to pass in the constructor is not obtained in the person object of new. Because there are no parameters passed in, it can't be assigned at all.
1.5 arrow function this binding
The ES6 arrow function needs to be discussed separately. It does not apply to the above four binding rules. There is no this in the arrow function
The direction of this in the arrow function depends on this in the outer scope. Who the outer scope or this in the function points to will point to.
function fn(){ return () =>{ console.log(this.name); } } let obj1 = { name='Gabrielle' }; let obj1 = { name='Gaby' } let bar = fn.call(obj1);//fn this points to obj1 bar.call(obj2); //Gabrielle
Q1: why is it not modified after binding again?
A2: characteristics of cuz arrow function: once this binding of the arrow function is successful, it cannot be modified again.
Q2: really can't it be modified?
A2: in fact, there is no solution. The arrow function this will be found from the upper scope like scope inheritance, so you can modify the outer function this to indirectly modify the arrow function this.
function fn(){ return () =>{ console.log(this.name); } } let obj1 = { name='Gabrielle' }; let obj1 = { name='Gaby' } fn.call(obj1)();//fn this points to obj1, and the arrow function this also points to obj1 fn.call(obj2)();//fn this points to obj2, and the arrow function this also points to obj2
keep going
There are many and miscellaneous knowledge points to be sorted out for JS in-depth understanding. To learn JS well, we must understand the logic and principles behind it, rather than simply know how to write code to use.