What underlies this JavaScript idiom: var self = this?
Solution 1
See this article on alistapart.com. (Ed: The article has been updated since originally linked)
self
is being used to maintain a reference to the original this
even as the context is changing. It's a technique often used in event handlers (especially in closures).
Edit: Note that using self
is now discouraged as window.self
exists and has the potential to cause errors if you are not careful.
What you call the variable doesn't particularly matter. var that = this;
is fine, but there's nothing magic about the name.
Functions declared inside a context (e.g. callbacks, closures) will have access to the variables/function declared in the same scope or above.
For example, a simple event callback:
function MyConstructor(options) {
let that = this;
this.someprop = options.someprop || 'defaultprop';
document.addEventListener('click', (event) => {
alert(that.someprop);
});
}
new MyConstructor({
someprop: "Hello World"
});
Solution 2
I think the variable name 'self' should not be used this way anymore, since modern browsers provide a global variable self
pointing to the global object of either a normal window or a WebWorker.
To avoid confusion and potential conflicts, you can write var thiz = this
or var that = this
instead.
Solution 3
Yes, you'll see it everywhere. It's often that = this;
.
See how self
is used inside functions called by events? Those would have their own context, so self
is used to hold the this
that came into Note()
.
The reason self
is still available to the functions, even though they can only execute after the Note()
function has finished executing, is that inner functions get the context of the outer function due to closure.
Solution 4
It should also be noted there is an alternative Proxy pattern for maintaining a reference to the original this
in a callback if you dislike the var self = this
idiom.
As a function can be called with a given context by using function.apply
or function.call
, you can write a wrapper that returns a function that calls your function with apply
or call
using the given context. See jQuery's proxy
function for an implementation of this pattern. Here is an example of using it:
var wrappedFunc = $.proxy(this.myFunc, this);
wrappedFunc
can then be called and will have your version of this
as the context.
Solution 5
As others have explained, var self = this;
allows code in a closure to refer back to the parent scope.
However, it's now 2018 and ES6 is widely supported by all major web browsers. The var self = this;
idiom isn't quite as essential as it once was.
It's now possible to avoid var self = this;
through the use of arrow functions.
In instances where we would have used var self = this
:
function test() {
var self = this;
this.hello = "world";
document.getElementById("test_btn").addEventListener("click", function() {
console.log(self.hello); // logs "world"
});
};
We can now use an arrow function without var self = this
:
function test() {
this.hello = "world";
document.getElementById("test_btn").addEventListener("click", () => {
console.log(this.hello); // logs "world"
});
};
Arrow functions do not have their own this
and simply assume the enclosing scope.
Thomas L Holaday
Updated on August 01, 2022Comments
-
Thomas L Holaday almost 2 years
I saw the following in the source for WebKit HTML 5 SQL Storage Notes Demo:
function Note() { var self = this; var note = document.createElement('div'); note.className = 'note'; note.addEventListener('mousedown', function(e) { return self.onMouseDown(e) }, false); note.addEventListener('click', function() { return self.onNoteClick() }, false); this.note = note; // ... }
The author uses self in some places (the function body) and this in other places (the bodies of functions defined in the argument list of methods). What's going on? Now that I've noticed it once, will I start seeing it everywhere?
-
steve over 10 yearsFor me the cogent point is that
self
has no special meaning. I personally prefer using a var named something other thanself
since it frequently confuses me, as I expect 'self' to be a reserved word. So I like your answer. And in the example of the OP, I'd prefervar thisNote = this
or similar. -
djheru about 10 yearsI usually use
_this
-
o_o_o-- almost 10 years@djheru +1. so much nicer than "
that
" (which my brain will never get used to). -
miphe over 9 years@prior I think it makes sense up until the last paragraph.
-
GreenAsJade over 9 years@JohnPaul ... this does provide an answer. It might not be the right answer, but how can you say that "it is being used to ... " is not an answer to "why did he do this"?
-
mattLummus about 9 years@steve agreed, although I try to avoid using this/self references in general as they are very brittle in terms of maintainability.
-
Mopparthy Ravindranath almost 9 yearsI started using "me" :)
-
Beejor almost 9 yearsUntil modern browsers start providing a global variable _this, that, or me.
-
Bergi over 8 yearsThere's absolutely no problem with using the name
self
as long as you declare it as avar
iable, it'll shadow the global. Of course if you forgot thevar
then it wouldn't work with any other name either. -
aaaaaa about 8 years@Bergi - One problem is that eslint won't catch it as an error if you forget to declare 'var self = this'.
-
Bergi about 8 years@aaaaaa It does not? Have you declared
self
as an implicit global to eslint somewhere? -
aaaaaa about 8 years@Bergi Nope - it's implied via the browser environment: "env": { "browser": true }
-
Duan Yao almost 8 years@Matian2040 Existing codes which use
var self = this
continue to work, because the globalself
is shadowed, as @Bergi said. However If someone tries to modify existing code without carefully check existing uses ofself
in the same scope, he/she may unintentionally shadow the globalself
and breaks the code. That's whyvar self = this
should be avoided. -
jatazoulja over 7 years@djheru I agree with the concept of this to annotate top level this, and for me if the scope gets even deeper prepending additional "" would work for me.
__this = this;
or it can be any prefix (except for $) :D -
Farhana Naaz Ansari almost 6 yearsYou should add some explanation with code that what you did special.
-
Benjamin R over 5 yearsOr – shock, horror! – why not pass the actual relevant thing as an argument to your function (closure)? Why the hell are you referencing out of scope state, why the hell is anyone programming like this? There is never any real reason to do this. Instead
.addEventListender("click", (x) => { console.log(x); });
You've explained the how and why very clearly, and I agree using arrow functions makes more sense, but still... this is just terrible, lazy, messy, programming. -
Elliot B. over 5 yearsIn JavaScript, referring back to the parent scope is extremely common and necessary. It's a fundamental part of the language. Your suggestion to pass in the parent scope as an argument on the event handler isn't actually possible. Also, in ES6, arrow functions use lexical scoping — 'this' refers to it's current surrounding scope and no further -- it's not "referencing out of scope state" or anything like that.
-
Bob Stein over 4 yearsAppears that article morphed into using
var that = this;
-
Bob Stein over 4 years
-
Pradeep Kumar over 4 years@BobStein Thanks. I'll update the answer accordingly.
-
Nithin B about 2 yearsSome explanation would be helpful here. You can see difference if you do var temp = thisss.sayHi and then call temp(). Now this.firstname will give undefined and that.firstname will give value because of closure created because of that variable.