In a javascript file, when I declare a function using function
keyword, I can placed my function after my caller function, something like
// test.js
function myCaller() {
foo('hello world'); // this works!
this.foo('hello world'); // this works!
}
function foo(text) {
console.log('foo called!', text);
}
myCaller()
but if I turned the foo
into an arrow function, and placed it at same position, then in myCaller
function, it said foo
is not defined, also it won't work if I use this
keyword to locate the foo
function, which I assume the this
refers to global/document level
// test.js
function myCaller() {
foo('hello world'); // es-lint warning: 'foo' was used before it was defined
this.foo('hello world'); // compilation error: foo is not defined
}
const foo = (text) => {
console.log('foo called!', text);
}
myCaller();
- I was wrong, I thought the 2nd approach without using this
does not work because of javascript compilation error of not defined
, but it was actully my eslint error - 'foo' was used before it was defined
, does it mean it's not recommend to do this way?
Why is that and does it mean we have to declare the arrow function always above caller
function? Is there any alternative way to solve that?
const foo = (text) => {
console.log('foo called!', text);
}
// test.js
function myCaller() {
foo('hello world'); // this works! no es-lint warning now
this.foo('hello world'); // no compilation error but there is a run-time error : 'this.foo is not a function'
}
myCaller();
In addition, I found when declare the arrow function inside a javascript class, it would work with this
keyword only with caller function being arrow function as well, if caller function is with function
keyword, this will not work...
// myTest.js
class myTest {
myCaller() {
foo('hello world'); // compilation error: foo is undefined
}
myCaller2 = () => {
this.foo('hello world'); //this works!
}
foo = (text) => {
console.log('foo called!', text);
}
}
new myTest().myCaller();
new myTest().myCaller2();
Any variables (except let
and const
variables) that you declare or functions that you define in global context (say, directly in test.js) will be attached to Window object. So, when you write,
// test.js
function myCaller() {
foo('hello world'); // this works!
this.foo('hello world'); // this works!
}
function foo(text) {
console.log('foo called!', text);
}
myCaller()
Both myCaller
and foo
are attached to window object as properties. Now you can refer to them either directly like foo()
(this is implicit here) or this.foo()
or even window.foo()
. Since js uses hoisting, these variables or functions are first attached to the context and then starts executing.
But const
and let
are not attached to the Window object (otherwise they would be accessible everywhere, behaving exactly like var
). So when you write
// test.js
function myCaller() {
foo('hello world');
this.foo('hello world');
}
const foo = (text) => {
console.log('foo called!', text);
}
myCaller();
Javascript engine scans through the entire script to see if there are any variables or functions defined. In this hoisting phase, if it finds a const
or let
, it allocates memory for them but won't make them part of Window object. So, when you are referring to this
in global context, it is referring to window object and foo
is not a property of window object. That is why, even if you put const foo
above myCaller
definition, it won't work.
In case of class, if you try to call foo()
directly without referring to this, it tries to access it from the enclosing contexts, where it is not defined in your example. So it throws error. If you define another foo()
outside the class with var
or directly as foo = (text) => ...
, it will work.
(The this
may not be always referring to global context. Functions and classes can have their own custom context, and this
would refer to that context. But when no custom context is defined by the functions or classes, the global context will be the one the this
keyword would be referring to. The this
is undefined for functions and classes by default in strict mode. There are several such caveats to be taken into consideration.)