Introduced
This is one of the most intriguing features in JavaScript, and the first step in learning this is to understand that this is not a scope to point to a function or to a function. This is actually the binding that occurs when a function is invoked, and where it points to depends entirely on where the function is invoked.
Why do I need to bind this
This refers to the current context environment, which is easily changed inadvertently:
var info = "This is global info";
var obj = {
info: ' This are local info ',
getinfo:getinfo
}
function GetInfo () {
Console.log ( this.info);
}
Obj.getinfo ()//this is local info
getInfo ()//this is global info The current context is modified
In the example above, we create an attribute GetInfo inside the object, reference to the GetInfo under global scope, and its function is to print the value of info in the current context, and when we use obj.getInfo
it, it prints out the value of the info inside the object. This point points to the object. And when we use the global function, it prints the value of the info variable in the Global environment, when this points to the global object.
This example tells us:
1, the same function, the way the call is different, this point will be different, the result will be different.
2. When the value of an attribute within an object is a reference type, this point does not always bind to the original object.
Second, there is also inadvertently this loss of the situation:
var info = "This is global info";
var obj = {
info: ' This are local info ',
getinfo:function getInfo () {
console.log (this.info);
var GetInfo2 = function GetInfo2 () {
console.log (this.info);
}
GetInfo2 ();
}
Obj.getinfo ();
This is the local info
//this is global info
In the example above, object obj defines a GetInfo method in which a new function is defined, and the value of the Info property of the outermost object is also desired, but it backfired that this of the function inside the function was incorrectly pointing to the window global object, which caused the error.
The solution is also very simple, the outermost definition of a variable, store the current lexical scope of this point to the location, according to the scope of the variables, the function can also access the variable inside, so that the upper function inside this is the real point.
var info = "This is global info";
var obj = {
info: ' This are local info ',
getinfo:function getInfo () {
console.log (this.info);
var self = this; Save the outer this to the variable
var GetInfo2 = function GetInfo2 () {
console.log (self.info);//point to the outer variable represents this
}
GetInfo2 ();
}
Obj.getinfo ();
This is the local info//this are local
info
However, there may be problems with the self variable, which is equivalent to a reference to the Obj object, which may inadvertently modify the entire object at some point, and you need to declare multiple variables when you need to get this point in multiple environments, which is not conducive to management.
There are ways to bind the context of the current environment to ensure the security of programmatic content without declaring a variable like self.
How to bind this
1. Call, apply
Call and apply are the Function.prototype
two functions defined on, and their role is to correct the context in which the function is executed, which is the point of this.
Take call as an example, the above Anotherfun want to output the local thing to modify this:
...
var anotherfun = Obj.getinfo;
Anotherfun.call (obj)//this is local info
Parameters for function calls:
Function.prototype.call(context [, argument1, argument2 ])
Function.prototype.apply(context [, [ arguments ] ])
As you can see from here, the first parameter of call and apply is necessary, accept a modified context, and the second argument is optional, and the difference between them is that, when called starts with the second argument, the value of the incoming calling function is accepted as a single occurrence, and apply is to accept an array to pass in.
function Add (NUM1, num2, num3) {return
NUM1 + num2 + num3;
}
Add.call (NULL, 10, 20, 30);
add.apply (NULL, [10, 20, 30]);//60
When the accepted context is undefined or null, it is automatically corrected to the global object, as in the example window
2. Using Function.prototype.bind to bind
ES5 in the Function.prototype
new bind
method, which accepts a context object that needs to be bound, and returns a copy of the called function, it can also append parameters to achieve the function of Gerty.
Function.prototype.bind (context[, argument1, argument2])
/function Gerty partial
function Add (NUM1, num2) {return
NUM1 + num2;
}
var anotherfun = window.add.bind (window, ten);
Anotherfun (20); 30
At the same time, he returns a copy of the function and binds the function to the incoming context forever.
...
var anotherfun = obj.getInfo.bind (obj)
anotherfun ();//this is local info
Polyfill
Polyfill is a solution for backward compatibility, how to use the Bind method on old browsers that do not support ES5, you need to rewrite a bind method using the old method.
if (! Function.prototype.bind) {
Function.prototype.bind = Function (obj) {
var self = this;
return function () {
self.call (obj);}}}
The above notation implements the return of a function and modifies the context to an incoming parameter, but does not implement the Gerty section.
...
Function.prototype.bind = function (obj) {
var args = Array.prototype.slice.call (arguments, 1);
Record all the first incoming arguments
var self = this;
return function () {
self.apply (obj, Args.concat (Array.prototype.slice.call (arguments)));
}
When binding is used with BIND, it is no longer possible to fix this point by call,apply, so bind binding is also known as hard binding.
3. Bind using the New keyword
In JS, the function has two kinds of invocation, one is to call directly, one is to construct the call through the New keyword.
function Fun () {Console.log ("function called")}
///Direct call to
fun ()//function called
//Construct call
var obj = New Fun ()//function called
What is the difference between a normal call and a constructor call that uses the New keyword?
To be exact, the New keyword simply adds a few more steps, based on the invocation of the function, including the fix this pointer to the return object.
var a = 5;
function Fun () {
THIS.A = ten
}
var obj = new Fun ();
OBJ.A//10
Precedence comparisons for several binding methods
The following example is used to compare the priority weights of several binding states
var obj1 = {
info: ' This is Obj1 ',
getInfo: () => Console.log (this.info)
}
var obj2 = {
info: "This Is Obj2 ",
getInfo: () => Console.log (this.info)
}
1. Call,apply and default pointing comparison
First of all, obviously, depending on the frequency of use, call and apply are higher precedence than direct calls.
Obj1.getinfo ()//this is obj1
obj2.getinfo ()//this are obj2
obj1.getInfo.call (obj2)//this is Obj2
Obj2.getInfo.call (obj1)//this is obj1
Using call and apply compared to using new?
This time there will be a problem, because we have no way new function.call(something)
to run code like this. So, we return a new function through the Bind method, and then we judge the priority by new.
var obj = {}
function foo (num) {
this.num = num;
}
var setnum = foo.bind (obj);
Setnum (ten);
Obj.num//10
var obj2 = new Setnum;
Obj.num//10
obj2.num//20
As we can see from this example, when you use new to construct a call, a new object is returned and the this is fixed on the object, but it does not change the contents of the object before it.
So the problem is, the polyfill of bind we wrote above obviously don't have the ability. And on the MDN there is a Polyfill method of bind, and its method is as follows:
if (! Function.prototype.bind) {
Function.prototype.bind = function (othis) {
if (typeof this!== "function") {
throw new TypeError ("Function.prototype.bind-what is trying to being bound is not
callable");
var Aargs = Array.prototype.slice.call (arguments, 1),
ftobind = this,
Fnop = function () {},
Fbound = function () {return
ftobind.apply, this instanceof Fnop?
This:othis | | This,
aargs.concat (Array.prototype.slice.call (arguments)));
Fnop.prototype = This.prototype;
Fbound.prototype = new Fnop ();
return fbound;}
The above Polyfill first determines whether the object that needs to be bound is a function and prevents it from being used Function.prototype.bind.call(something)
, something is not a function causing an unknown error. Then let the Fbound function that needs to be returned inherit from this and return Fbound.
Special cases
Of course, in some cases, the this pointer points to some surprises as well.
Arrow function
In ES6, there is a new way of defining functions, using "=>" to define a function, within which the pointer to this will not change and always point to the outermost lexical scope.
var obj = {
num:1,
getnum:function () {return
function () {
//this lost
console.log (this.num);
This here points to window
}
}
Obj.getnum () ();//undefined
var obj2 = {
num:2,
getnum: function () {return
() => console.log (this.num);
The arrow function internally binds the external getnum this, the external this points to the invoked object
}
Obj2.getnum () ();//2
Soft binding
The Bind method provided above can be pointed by force correction, and cannot be modified by call,apply. If we want to be able to have a bind effect, but we can also fix the function two times with call and apply, we need to rewrite a Function.prototype
method that is built on, and we name it "soft binding."
if (! Function.prototype.softBind) {
Function.prototype.softbind = Function (obj) {
var self = this;
var args = Array.prototype.slice.call (arguments, 1);
return function () {return
self.apply (!this | | this = = (Window | | global))?
Obj:this,
args.concat (Array.prototype.slice.call (arguments)));}}
The magical uses of Bind,call
In weekdays, when we need to turn a pseudo array element into a normal array element, we often pass the Array.prototype.slice
method, as in the example above. Turn the arguments object into a real array object, using the Array.prototype.slice.call(arguments)
transform. However, each use of this method is too long and cumbersome. So sometimes we write this:
var slice = Array.prototype.slice;
Slice (arguments);
Error
The same problems are also found in:
var QSA = Document.queryselectorall;
QSA (something);
Error
The problem above is now, the built-in slice and Queryselectorall method, which is used internally, when we simply reference, this becomes the Global environment window at run time, and of course it can cause errors. We simply need to use bind to create a copy of the function.
var QSA = document.querySelectorAll.bind (document);
QSA (something);
Similarly, because call and apply are also functions, you can invoke the Bind method on them. This allows the copy of the returned function to have the function of correcting the pointer itself.
var slice = Function.prototype.call.bind (Array.prototype.slice);
Slice (arguments);
Summarize
The above is the entire content of this article, I hope the content of this article for everyone's study or work can bring certain help, if you have questions you can message exchange.