问题
I'm learning how the value of "this" binds in JavaScript. In the following example, is it correct to say that "this" binds to the getFriends() method instead of the "details" object, which is the reason this.name = "" instead of this.name = "Joe"?
const details = {
name: 'Joe',
friends: [ 'Bob', 'Alex' ],
getFriends: function() {
this.friends.forEach( function( friend ) {
console.log( this.name + " is friends with " + friend );
} );
}
};
details.getFriends();
// Output:
// is friends with Bob
// is friends with Alex
As I understand from my studies, "this" does not bind one level up in the parent scope, right? That's one benefit of using arrow functions, which bind "this" to the parent scope.
回答1:
Quoting from w3schools
In a method, this refers to the owner object.
Alone, this refers to the global object.
In a function, this refers to the global object.
In a function, in strict mode, this is undefined.
In an event, this refers to the element that received the event.
Methods like call(), and apply() can refer this to any object.
https://www.w3schools.com/js/js_this.asp
回答2:
No when you run the code this way this
is pointing to the global window object. You can console.log
the value of this
. To test it, you can also place a key of my_name
on the window (don't use name, since that's used by the window). Now when you run the code, you'll see the global:
const details = {
my_name: 'Joe',
friends: [ 'Bob', 'Alex' ],
getFriends: function() {
this.friends.forEach( function( friend ) {
console.log( this.my_name + " is friends with " + friend );
} );
}
};
window.my_name = "What?"
details.getFriends();
FYI: forEach
takes a second value that you can use to specify what this
will be in the callback. So this works for example:
const details = {
my_name: 'Joe',
friends: [ 'Bob', 'Alex' ],
getFriends: function() {
this.friends.forEach( function( friend ) {
console.log( this.my_name + " is friends with " + friend );
}, this ); //<-- pass this into the forEach
}
};
details.getFriends();
Of course, you can always use an arrow function too.
回答3:
The keyword this
refers to the current execution context.
By default this
in a function is set to the global context which is always the window object in a browser:
function foo() {
return this;
}
console.assert(foo() === window);
However when called as a constructor, the new
operator sets this
to an object created from the function prototype. That context is unique to each instance.
function foo() {
return this;
}
console.assert(new foo() !== window);
console.assert(new foo() !== new foo());
When an object has a method, the this
in that method is that object by default:
const question = {
ask: function () {
return this;
}
};
console.assert(question.ask() === question);
Now here is why the current execution context matters.
If you take that method outside of its object then that method context will default to the global context:
const question = {
ask: function () {
return this;
}
};
const ask = question.ask;
console.assert(ask() === window);
To solve that problem you can use either bind
, call
or apply
:
const question = {
ask: function () {
return this;
}
};
const ask = question.ask;
console.assert(ask.bind(question)() === question);
console.assert(ask.call(question) === question);
console.assert(ask.apply(question) === question);
You must have heard of arrow functions which bind this
to the context that was available at the time the function was defined.
Previously we had to save this
in a variable (usually called that
) to refer to the right context. (Or use bind
.)
function foo() {
const that = this;
// By the time the function executes, the execution context
// will be different even though we invoked the function
// as a constructor.
setTimeout(function () {
console.assert(that !== this);
console.assert(this === window);
}, 100);
}
new foo();
That technique became deprecated with arrow functions:
function foo() {
setTimeout(() => {
console.assert(this !== window);
}, 100);
}
new foo();
However remember that functions are lexically scoped, so this will not give you the expected result:
const question = {
ask: () => {
return this;
}
};
console.assert(question.ask() === window);
Why? At the time the arrow function was defined, the only context available in the lexical scope was the global context.
来源:https://stackoverflow.com/questions/56157472/the-binding-of-this