1. Introduction
JS “this, apply, call and bind” is a classic interview question. Understand the difference between “this” and “call”, “apply” and “bind” to reduce errors in business code and solve the problem.
2. This point
In ES5, this always refers to the object that called it last.
<script>
var name = "zhangsan";
function a() {
var name = "lisi";
console.log(this.name); // zhangsan
console.log("inner:" + this); // inner: Window
}
a();
console.log("outer:" + this) // outer: Window
</script>
Copy the code
This always refers to the object where it was last called, a(); The global object window, which is equivalent to window.a();
TypeError: Cannot read property ‘name’ of undefined Uncaught TypeError: Cannot read property ‘name’ of undefined
<script>
var name = "zhangsan";
var a = {
name: "lisi",
fn: function () {
console.log(this.name); // lisi
}
}
a.fn();
</script>
Copy the code
In this case, the function fn is called from object A, so the printed value is the value of name in a.
<script>
var name = "zhangsan";
var a = {
name: "lisi",
fn: function () {
console.log(this.name); // lisi
}
}
window.a.fn()
</script>
Copy the code
The reason I print lisi is because “this always refers to the last object to call it”, and the last object to call it is still object A
<script>
var name = "zhangsan";
var a = {
fn: function () {
console.log(this.name); // undefined
}
}
window.a.fn();
</script>
Copy the code
Why would I print undefined here? This is because, as just described, fn is called by object A, that is, fn’s internal this is object A, and object A does not define name, so log’s this.name value is undefined.
This always refers to the object on which fn was last called, because the object on which FN was last called is A. Therefore, even if a does not have the name attribute, it does not continue to look for this.name in the previous object.
<script>
var name = "zhangsan";
var a = {
name: "lisi",
fn: function () {
console.log(this.name); // zhangsan
}
}
var f = a.fn;
f();
</script>
Copy the code
Why not lisi, although this is because a object method of fn was assigned to the variable f, but no calls, “this will always point to the last call it the object of”, because the f did not call, so the fn () the last is still be invoked by the window. So this refers to the window.
As you can see, the direction of this is not always determined at creation time. In ES5, this always refers to the object that last called it.
<script> var name = "zhangsan"; var a = { name: "lisi", func1: function () { console.log(this.name) }, func2: function () { setTimeout(function () { this.func1() }, 100); }}; a.func2() // Uncaught TypeError: this.func1 is not a function </script>Copy the code
<script> var name = "zhangsan"; var a = { name: "lisi", func1: function () { console.log(this.name) }, func2: function () { setTimeout(() => { this.func1() }, 100); }}; a.func2() // lisi </script>Copy the code
Without the arrow function, an error is reported because the last object to call setTimeout is the window, but there is no func1 function in the window.
The arrow function in ES6 avoids the use of this in ES5. The arrow function’s this always points to this when the function is defined, not when it is executed. Arrow functions do not have a this binding, and its value must be determined by searching the scope chain. If the arrow function is contained by a non-arrow function, this is bound to the nearest non-arrow function’s this; otherwise, this is undefined.
<script> var name = "zhangsan"; var a = { name: "lisi", func1: function () { console.log(this.name) }, func2: function () { var _this = this; setTimeout(function () { _this.func1() }, 100); }}; a.func2() // lisi </script>Copy the code
Without ES6, we would first store the object on which this function is called in the _this variable, and then use the _this variable throughout the function so that _this does not change.
3. Use apply, call, and bind to solve this pointing problem
3.1 the apply
<script> var name = "zhangsan"; var a = { name: "lisi", func1: function () { console.log(this.name) }, func2: function () { setTimeout(function () { this.func1() }.apply(a), 100); }}; a.func2() // lisi </script>Copy the code
3.2 the call
<script> var name = "zhangsan"; var a = { name: "lisi", func1: function () { console.log(this.name) }, func2: function () { setTimeout(function () { this.func1() }.call(a), 100); }}; a.func2() // lisi </script>Copy the code
3.3 the bind
<script> var name = "zhangsan"; var a = { name: "lisi", func1: function () { console.log(this.name) }, func2: function () { setTimeout(function () { this.func1() }.bind(a)(), 100); }}; a.func2() // lisi </script>Copy the code
4. Bind is different from apply and call
<script> var a = {fn: function (a,b) {console.log(a + b) // } } var b = a.fn; B.b ind (a, 1, 2) < / script >Copy the code
<script> var a = { fn : function (a,b) { console.log( a + b) // 30 } } var b = a.fn; B.b ind (a, 10, 20) () < / script >Copy the code
The bind() method creates a new function that, when called, sets its this keyword to the supplied value and, when called, provides a given sequence of arguments before any supply.
So we can see that bind creates a new function that we have to call manually.
Conclusion: Call and apply execute a function after changing its this context, while bind returns a function after changing its context.
5. The bind
<script> if (! Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this ! == "function") { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } var aArgs = Array. Prototype. Slice. The call (the arguments, 1), fToBind = this, / / here this point to the objective function fNOP = function () {}, fBound = function () { return fToBind.apply(this instanceof fNOP ? This // where this is the obj generated when new obj() is called: OThis | | this, / / if oThis invalid will fBound bound to this / / transfer through the bind parameters and call the merge, And as the final parameters aArgs. Concat (Array) prototype. Slice. Call (the arguments))); }; // Copy the prototype object of the target function into the new function, because the target function may be used as a constructor. fBound.prototype = new fNOP(); return fBound; }; } </script>Copy the code
6. The difference between call and apply
fn.call(obj, arg1, arg2, arg3...) ;Copy the code
fn.apply(obj, [arg1, arg2, arg3...] );Copy the code
The difference between call and aplly is that the first parameter of call and aplly is the object to change the context. Call is presented as a list of parameters starting with the second parameter. Apply takes as its second parameter an array of parameters other than the change context object.
6.1 Finding the maximum and minimum values in an array
Var arr = [1,2,33,44,55, -1]; Math.max.apply(Math, arr); Math. Max. Call (Math,,2,33,44,55 1, 1); Math.min.apply(Math, arr); ,2,33,44,55 Math. Min. Call (Math, 1, 1);Copy the code
6.2 Converting a pseudo-Array to an array
<script>
var obj = {
0: 'zhangsan',
1: 'lisi',
2: 'wanwu',
length: 3
}
var arr = Array.prototype.slice.call(obj);
console.log(arr) // ["zhangsan", "lisi", "wanwu"]
</script>
Copy the code