This keyword in JavaScript
This keyword in JavaScript
The keyword "this" in JavaScript Functions does not refer to Itself (Itself). For example:
function foo(num) { console.log( foo: + num ); // keep track of how many times `foo` is called this.count++;}foo.count = 0;var i;for (i=0; i<10; i++) { if (i > 5) { foo( i ); }}// foo: 6// foo: 7// foo: 8// foo: 9// how many times was `foo` called?console.log( foo.count ); // 0
In the above example, although foo () is executed four times, foo. count is still 0, indicating that this does not refer to the foo function itself. So what value does the count ++ execute increase? In fact, we have created a global variable count, which is a variable in the window. Its initial value is NaN. Even if it is increased four times, its value is NaN.
If the above example is changed to the following, it is easy to understand:
function foo(num) { console.log( foo: + num ); // keep track of how many times `foo` is called data.count++;}var data = { count: 0};var i;for (i=0; i<10; i++) { if (i > 5) { foo( i ); }}// foo: 6// foo: 7// foo: 8// foo: 9// how many times was `foo` called?console.log( data.count ); // 4
However, we do not use the this keyword here. We just choose to avoid this and use the Lexical scope method.
If we want to reference itself within a function, we can only use lexical identifier (variable) to point to itself, as shown below:
function foo() { foo.count = 4; // `foo` refers to itself}
This method is effective for functions with function names, but it is powerless for anonymous functions, such as the following:
setTimeout( function(){ // anonymous function (no name), cannot // refer to itself}, 10 );
We can't do anything about this, but there is a method that is not recommended (currently obsolete) to reference the function itself: arguments. callee, in fact, our best way is to avoid using anonymous functions when you need to reference the function itself, so as to avoid the above problems.
Therefore, if we want to reference our own functions at the beginning, we can use its own function name (identifier:
function foo(num) { console.log( foo: + num ); // keep track of how many times `foo` is called foo.count++;}foo.count = 0;var i;for (i=0; i<10; i++) { if (i > 5) { foo( i ); }}// foo: 6// foo: 7// foo: 8// foo: 9// how many times was `foo` called?console.log( foo.count ); // 4
In the above example, we seem to have avoided the this keyword, but in the above example, we need to reference the function itself and cannot use this keyword.
If we must use the this keyword to refer to the function itself, we can do this:
function foo(num) { console.log( foo: + num ); // keep track of how many times `foo` is called // Note: `this` IS actually `foo` now, based on // how `foo` is called (see below) this.count++;}foo.count = 0;var i;for (i=0; i<10; i++) { if (i > 5) { // using `call(..)`, we ensure the `this` // points at the function object (`foo`) itself foo.call( foo, i ); }}// foo: 6// foo: 7// foo: 8// foo: 9// how many times was `foo` called?console.log( foo.count ); // 4
Another misunderstanding of this is that this refers to the lexical scope of the function. In You Dont Know JS, there is a paragraph about this:
To be clear, this does not, in any way, refer to a function's lexical scope. it is true that internally, scope is kind of like an object with properties for each of the available identifiers. but the scope "object" is not accessible to JavaScript code. it's an inner part of the Engine's implementation.
See the following example:
function foo() { var a = 2; this.bar();}function bar() { console.log( this.a );}foo(); //undefined
The above code tries to build a bridge between foo () and bar () lexical scopes through this, so bar () is used to obtain the variable a of the inner scope of foo, such a bridge actually does not exist.
So what is this mechanism? In fact, this is a runtime binding, rather than an author-time binding, that is, a function is bound based on its context During calling.
In You Dont Know JS, there is a saying about this mechanism:
'Eas' is not an author-time binding but a runtime binding. it is contextual based on the conditions of the function's invocation. this binding has nothing to do with where a function is declared, but has instead everything to do with the manner in which the function is called.
When a function is invoked, an activation record, otherwise known as an execution context, is created. this record contains information about where the function was called from (the call-stack), how the function was invoked, what parameters were passed, etc. one of the properties of this record is the this reference which will be used for the duration of that function's execution.
As mentioned above, this is bound based on its Call-site when a function is called. What is Call-site?
Call-site: the location in code where a function is called (not where it's declared ).
So how to determine the call-site of the function,
Go locate where a function is called from
However, it is not easy to determine the call-site of the function. Therefore, we use another method to find the call-stack of the function:
The stack of functions that have been called to get us to the current moment in execution
The following is an example to illustrate the relationship between call-site and call-stack:
function baz() { // call-stack is: `baz` // so, our call-site is in the global scope console.log( baz ); bar(); // <-- call-site for `bar`}function bar() { // call-stack is: `baz` -> `bar` // so, our call-site is in `baz` console.log( bar ); foo(); // <-- call-site for `foo`}function foo() { // call-stack is: `baz` -> `bar` -> `foo` // so, our call-site is in `bar` console.log( foo );}baz(); // <-- call-site for `baz`
We can debug and view the call-stack function through the debugger of the dev Tool in the browser.
After we know the call-site, let's look at the four rules for binding this:
1. Default Binding
This is the most common binding rule, that is, this points to the global object. See the example below:
function foo() { console.log( this.a );}var a = 2;foo(); // 2
In strict mode, this points to undefined:
function foo() { use strict; console.log( this.a );}var a = 2;foo(); // TypeError: `this` is `undefined`
Note that if foo () is not in strict mode, this still points to the global object:
function foo() { console.log( this.a );}var a = 2;(function(){ use strict; foo(); // 2})();