This question already has answers here:
Methods in ES6 objects: using arrow functions
(6 answers)
How does the "this" keyword in Javascript act within an object literal? [duplicate]
(4 answers)
Closed 5 years ago.
I am trying to understand arrow functions in ECMAScript 6.
This is the definition I came across while reading:
Arrow functions have implicit this binding, which means that the
value of the this value inside of an arrow function is aways the
same as the value of this in the scope in which the arrow function
is defined!
According to the definition, I believe this for an arrow function should contain the same block level values that the arrow function was defined in.
Code:
var test = {
id: "123123",
k: {
laptop: "ramen",
testfunc: () => console.log(this)
}
}
console.log(test.k.testfunc);
However, I am getting this result from the code
function testfunc() {
return console.log(undefined);
}
What I thought I would get would be an output of:
{"laptop": "ramen"}
if I ran this
console.log(test.k.testfunc());
Let's transform into the equivalent ES5 code:
var test = {
id: "123123",
k: {
laptop: "ramen",
testfunc: function(){return console.log(this)}.bind(this)
}
}
Remember that this depends on how you call the function. The outer this isn't inside a function, so it will default to undefined in strict mode.
Simplified scenario below:
console.log(this) // undefined
var test = {
a: this // same `this` as above
}
You are defining the arrow function in the same scope that you defined var test. If you are defining test in the global scope, then the arrow function's context will be the global scope too.
If you are defining test inside of a method, the arrow function will share the method's context.
function method() {
const self = this;
const test = {
foo: () => console.log(self === this);
}
test.foo()
// console: true
}
Related
This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
What does "this" refer to in arrow functions in ES6?
(10 answers)
Closed 1 year ago.
I'm new to javascript and having trouble understanding the difference between arrow function and normal function when including this keyword, here is the example I read from MDN:
var obj = { // does not create a new scope
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log(this.i, this);
}
}
obj.b(); // prints undefined, Window {...} (or the global object)
obj.c(); // prints 10, Object {...}
In this example arrow function b() can not access i attribute in the object because it references the window
var obj = {
count : 10,
doSomethingLater : function(){ // of course, arrow functions are not suited for methods
setTimeout( () => { // since the arrow function was created within the "obj", it assumes the object's "this"
this.count++;
console.log(this.count);
}, 300);
}
}
obj.doSomethingLater(); //log 11 on the console
However, in the second example, code within the arrow function can access the count attribute. Both functions are defined within the object but only the second function can access the object's attribute, could someone give me some hints why is that? Thanks in advance!
This question already has answers here:
Can you bind 'this' in an arrow function?
(14 answers)
Closed 4 years ago.
I'm calling .bind(this) on an async function defined in another module inside of a class constructor.
The class is as below
class CannedItem {
constructor (config) {
...
this._fetch = config.fetch.bind(this)
...
}
...
}
The function is something like
module.exports = [
{
...
fetch: async () => {
// Want to refer to 'this' bound to the CannedItem object here
}
}
]
However when the function is called, this is bound to an empty object.
Confusingly Visual Studio Code debugger has the object in scope bound as this in the debugger window, see attached screenshot, however inspecting the variable in the console lists it as undefined. This looks to me like there is a bug. Is this the case or am I misusing .bind()?
The only thing that seems a little unusual is the async function. I tried searching for issues with async and .bind() but no dice.
I am running NodeJs 8.11.1 and the latest VSCode (1.30.2)
You can't rebind arrow functions because this is fixed to the lexically defined this. You need a regular function if you plan on using bind() or any of its relatives:
class CannedItem {
constructor(config) {
this.myname = "Mark"
this._fetch = config.fetch.bind(this)
}
}
let obj = {
fetch: async() => { // won't work
return this.myname
// Want to refer to 'this' bound to the CannedItem object here
}
}
let obj2 = {
async fetch() { // works
return this.myname
// Want to refer to 'this' bound to the CannedItem object here
}
}
// pass arrow function object
let c1 = new CannedItem(obj)
c1._fetch().then(console.log) // undefined
// pass regular function object
let c2 = new CannedItem(obj2)
c2._fetch().then(console.log) // Mark
As a bonus, if you use a regular function, you might not need bind().
this._fetch = config.fetch
will work if you call it from the instance.
This question already has answers here:
Accessing variables from other functions without using global variables
(10 answers)
Closed 5 years ago.
Using the following code how can I access a from inside log2?
(function() {
function log() {
var a = "string";
}
log()
function log2() {
console.log(log.a);
}
console.log(log);
log2();
})()
Variables declared with the var keyword in JavaScript are function-scoped. This means that they cannot be accessed from outside the function they were declared in without returning them. The solution is to declare the variable within your outer immediately-invoked function, which will enclose the variable and make it available to the two inner functions:
(function() {
var a;
function inner1 () {
a = 'string';
}
function inner2 () {
console.log(a);
}
inner1();
inner2(); // => logs 'string'
})()
console.log(a); // => logs undefined, because a is enclosed
This question already has answers here:
Are 'Arrow Functions' and 'Functions' equivalent / interchangeable?
(4 answers)
Closed 6 years ago.
I have two cases
const test = {
foo: function (){
this.bar();
},
bar: function (){
console.log('bar');
}
}
test.foo();
in this case, everything works correctly.
const test = {
foo: () => {
this.bar();
},
bar: () => {
console.log('bar');
}
}
test.foo();
In second case I get error:
Uncaught TypeError: Cannot read property 'bar' of undefined
I know I can wrote test.bar() in foo function, but I'm interested why this not available in arrow functions scope in this case.
Normally, the value of this in a function depends on how that function is called.
Arrow functions import the value of this from the scope in which the function was created.
In the middle of an object literal, the value of this will depend on what is around the object literal, but certainly won't be the object itself.
This question already has answers here:
Arrow Functions and This [duplicate]
(5 answers)
Closed 7 years ago.
Why does o.foo() print the global object to the console?
let o = {
foo: () => console.log(this),
bar() { console.log(this); }
};
o.foo(); // Global object / undefined
o.bar(); // o
I thought the equivalent of the arrow function might be something like this (but it's not):
let o = {
foo: function() {
console.log(this);
},
bar() {
console.log(this);
}
};
o.foo(); // o
o.bar(); // o
Arrow functions retain the this of the surrounding execution context from when they were declared. They don't change this all the time, like normal methods do.
In your example, there is no execution context surrounding foo, so this is undefined. This is the same behavior as a function declared using the function keyword at the same scope and called in the same way. You can test that with:
let foo = () => { return this; }
console.log(foo() === undefined);
From the spec at 14.2.16:
Any reference to arguments, super, or this within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function.
(emphasis mine)
Interestingly, when that arrow function is present in the global scope, the BabelJS transpiler simply outputs
"use strict";
var foo = function foo() {
return undefined;
};
as if that were the only correct behavior. Reading the spec, it doesn't seem quite as strict, but this does seem like the right thing to do.
It appears that you can end up with the global object as this if you manage to run ES6 code using arrows without modules. Per the spec at 10.2.1:
Global code is strict mode code if it begins with a Directive Prologue that contains a Use Strict Directive (see 14.1.1).
Module code is always strict mode code.
So it is possible to get ES6 code in a non-strict context. If that happens, then this will use the classical fallback and be set to window (in the spec at 9.2 as an undefined [[ThisMode]]).
In this example, there is no immediately enclosing function, thus no lexical scope to pick up, so this ends up undefined.
In your second example, the capture on this doesn't make a difference:
let o = {
foo: function() {
var self = this;
console.log(self);
},
bar() {
console.log(this);
}
};
The var self statement is within the function, so it won't do anything. If you were to do:
let o = {
foo: function() {
var self = this;
return function() {
console.log(self);
}
}(),
bar() {
console.log(this);
}
};
then it will have the behavior you expect (roughly), although this will still be undefined (or the global object) because you're not within a lexical environment to be captured.
If you were to use
class Foo {
bar() {
let baz = () => { return this; }
}
}
then bar could be transpiled down to
function bar() {
var _this = this;
var baz = function baz() {
return _this;
};
}
which does what you want. That only works because there is a surrounding context to be captured.