1. Why use this
This provides a more elegant way to implicitly “pass” an object reference, which is simpler and easier to reuse.
var me = {
name:'Kyle'
}
function identtify(){
return this.name;
}
identtify.call(me);// Kyle
// If you do not use this, you need to pass a context object to the identtify() display
var me = {
name:'Kyle'
}
function identtify(context){
return context.name;
}
identtify(me);// Kyle
Copy the code
2. This is two kinds of misunderstanding
2.1 Pointing to Self
Console.log () prints four times, meaning foo() was called four times, but why foo.count === 0? When foo. Count = 0, an attribute count is added to function object foo. But this in the function’s internal code this.count does not refer to a function object, so the root object is not the same even though the attribute name is the same. This. Count inadvertently creates a global variable count with a value of NaN.
function foo(num) {
console.log('foo:',num);
// Records the number of times foo is called
this.count++;
}
foo.count = 0;
for (var index = 0; index < 10; index++) {
if (index > 5) {
foo(index)
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// How many times foo is called
console.log(foo.count);/ / 0
Copy the code
To reference itself from within a function object, there are two ways:
// First, refer to a function object by a lexical identifier (variable) that refers to it
function foo(num) {
console.log('foo:',num);
// Records the number of times foo is called
foo.count++;
}
foo.count = 0;
for (var index = 0; index < 10; index++) {
if (index > 5) {
foo(index)
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// How many times foo is called
console.log(foo.count);/ / 4
// Second, force this to point to function object foo
function foo(num) {
console.log('foo:',num);
// Records the number of times foo is called
this.count++;
}
foo.count = 0;
for (var index = 0; index < 10; index++) {
if (index > 5) {
foo.call(foo,index)
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// How many times foo is called
console.log(foo.count);/ / 4
Copy the code
2.2 Its scope
In some cases it is right, but in other cases it is wrong. To be clear, however, this does not refer to the lexical scope of a function in any case. This code attempts to reference the bar function via this.bar(). This is a non-starter; It is also impossible to use this to connect the lexical scopes of foo() and bar() so that bar() can access variable A in the scope of foo(). You cannot use this to reference something inside a lexical scope.
function foo() {
var a = 2;
this.bar();
}
function bar() {
console.log(this.a);
}
foo();// this.bar is not a function
Copy the code
3. What is this? What kind of mechanism is it?
This is bound at run time, not at write time. The binding of this has nothing to do with the position of the function declaration; the reference of this depends entirely on the “call location” of the function.
4. Call location
The “call location” is where the function is called in the code, not where it is declared. How do I find “where function is called”? You need to analyze the “call stack” (that is, all the functions called to reach the current execution location), which is in the previous call of the currently executing function.
function baz() {
// Current call stack :baz
// Current calling location: global scope
console.log('baz');
bar();// Where bar is called
}
function bar() {
// Current call stack :baz -> bar
// Current call location: in baz
console.log('bar');
foo();// Foo's call location
}
function foo() {
// Current call stack :baz -> bar -> foo
// Current call location: in bar
console.log('foo');
}
baz();// Call location of baz
Copy the code
5. Binding rules
How does the location of a function call during execution determine the binding object for this? You first need to find the call location, and then determine which of the following four rules is true (if multiple rules are true, it has precedence, which I’ll talk about later).
5.1 Default Binding
In this case, the default binding for this is applied when the function is called, so this points to the global object. By analyzing the call location, foo() is called directly with an undecorated function reference, so only the default binding can be used.
function foo() {
console.log(this.a);
}
var a = 2;
foo();/ / 2
// Note: If strict mode is used, the default binding cannot be used for global objects because this is bound to undefined
function foo() {
// "use strict"
console.log(this.a);
}
var a = 2;
foo();// this is undefined
Copy the code
5.2 Implicit Binding
Implicit binding requires consideration of whether there is a context object at the calling location.
When foo() is called, the function references the context object obj. Implicit binding rules bind this in the function call to the context object, so this.a is equivalent to obj.a.
function foo() {
console.log(this.a);
}
var obj = {
a:2.foo:foo
}
obj.foo();/ / 2
// Note: only the last layer in the object attribute reference chain affects the call location
function foo() {
console.log(this.a);
}
var obj2 = {
a:42.foo:foo
}
var obj1 = {
a:2.obj2:obj2
}
obj1.obj2.foo();/ / 42
Copy the code
Implicit loss: Implicitly bound functions lose the binding object and the default binding is applied, so this is bound to the global object or undefined(strict mode)
In this case, although bar() is a reference to obj.foo, it refers to the foo function itself, so bar() is really a function call without any decorations, so the default binding is applied.
function foo() {
console.log(this.a);
}
var obj = {
a:2.foo:foo
}
var bar = obj.foo;// Function alias
var a = 3;// a is an attribute of the global object
bar()/ / 3
// An implicit loss occurs when the callback function is called (parameter passing is an implicit assignment, so the result is the same)
function foo() {
console.log(this.a);
}
function doFoo(fun) {
// fun refers to foo
fun();
}
var obj = {
a:2.foo:foo
}
var a = 3;
doFoo(obj.foo); / / 3
Copy the code
5.3 Displaying Binding
call(…) And the apply (…). Methods, their first argument is an object, which they bind to this, which they then specify when calling the function. (The difference between them is self-explanatory.)
/ / by foo. Call (...). , we can force foo to bind its this to obj when calling it
function foo() {
console.log(this.a);
}
var obj = {
a:2
}
foo.call(obj);/ / 2
Copy the code
However, showing bindings still doesn’t solve the problem of missing bindings mentioned above, so here’s how:
5.3.1 hard binding
Application scenario: Create a wrap function that passes in all parameters and returns all values received
/ / by foo. Apply (obj, the arguments); Force foo's this to be bound to obj. No matter how bar is later called, it will always manually call foo on obj.
function foo(b) {
console.log(this.a,b);
}
var obj = {
a:2
}
var bar = function () {
return foo.apply(obj,arguments);
}
bar(3); / / 2, 3
/ / because hard binding is a kind of common mode, method in ES5 provides a built-in Function. The prototype. The bind, bind (...). Returns a new hard-bound function, used as follows:
function foo(b) {
console.log(this.a,b);
}
var obj = {
a:2
}
var bar = foo.bind(obj);
bar(3); / / 2, 3
Copy the code
5.4 the new binding
In Js, constructors are simply functions that are called when the new operator is used. They don’t belong to a class, they don’t instantiate a class, they’re just normal functions called by the new operator. (There are no constructors, only “constructor calls” to functions.)
When a function is called with new, or when a constructor call occurs, the following operations are performed:
. Create a brand new object
.New objects will be connected by the implementation [[prototype]]
The new object will be bound to the function call’s this
. If the function returns no other object, the function call in the new expression automatically returns the new object
// Use new to call foo(...) Generates a new object and binds the new object to foo(...) This binding is called a new binding
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log(bar.a);/ / 2
Copy the code
6 priority
6.1 The default binding has the lowest priority
6.2 Displaying Binding > Implicit Binding
function foo(a) {
console.log(this.a);
}
var obj1 = {
a:2.foo:foo
}
var obj2 = {
a:3.foo:foo
}
// Obvious, show bind > Implicit bind
obj1.foo.call(obj2);/ / 3
obj2.foo.call(obj1);/ / 2
Copy the code
6.3 New Binding > Implicit Binding
function foo(a) {
this.a = a;
}
var obj = {
foo:foo
}
obj.foo(2);
console.log(obj.a);/ / 2
var bar = new obj.foo(4);
console.log(obj.a);/ / 2
// New binding > implicit binding
console.log(bar.a);/ / 4
Copy the code
6.4 New Binding > Show Binding
New and Call /apply cannot be used together and cannot be tested directly with new foo.call(obj), where hard binding is used to test their priority.
function foo(a) {
this.a = a;
}
var obj = {}
var bar = foo.bind(obj);
bar(2);
console.log(obj.a);/ / 2
var baz = new bar(3);
console.log(obj.a);/ / 2
// Unexpectedly, foo(...) After hard binding with bind, foo(...) This is bound to the specified object and returns a new function bar(...) . No matter how bar is later called, it will always manually call foo on the specified object.
// But why is this rebound when bar is called via new?
// Reason: built-in function.prototype.bind (...) Is used to determine whether the hard-bound function is called by new, and if so, to replace the hard-bound this with the newly created this
console.log(baz.a);/ / 3
Copy the code
Summary: New binding > Display Binding > Implicit binding > Default binding
7. There are always exceptions to the rule
7.1 Ignored this
If you pass null or undefined as a binding object for this to call, apply, or bind, these values will be ignored when called, and the default binding rules apply:
function foo(a) {
console.log(this.a);
}
var a = 2;
foo.call(null);/ / 2
Copy the code
7.2 Indirect Reference
Create an “indirect reference” to a function, in which case the default binding rules apply
function foo(a) {
console.log(this.a);
}
var a = 2;
var obj1 = {
a:3.foo:foo
}
var obj2 ={
a:4
}
obj1.foo();/ / 3
(obj2.foo = obj1.foo)();/ / 2
Copy the code
8. Arrow functions in ES6
Instead of using the four regular criteria for this, arrow functions determine this based on the outer (function or global) scope
function foo() {
return (a) = >{
/ / this inheritance foo ()
console.log(this.a); }}var obj1 = {
a:2
}
var obj2 ={
a:3
}
var bar = foo.call(obj1);
// The arrow function created inside foo() captures this that calls foo(). Since foo() 's this is bound to obj1, bar(which references the arrow function)' s this is also bound to obj1, and the arrow function 's binding cannot be modified. (Neither does New!)
bar.call(obj2);// 2, not 3
Copy the code