var obj = {
a: 2,
}
var a = 3;
const func = () => {
console.log(this.a);
}
function test() {
setTimeout(func, 100);
}
function test2() {
setTimeout(() => {
console.log(this.a);
}, 100);
}
test.call(obj); //3
test2.call(obj); //2
It seemed that the test and test2 are the same, but the returned result is different, what's the problem with 'this'?
with test arrow function, this will refer to the window object, and as var a = 3, the a will be assigned as a property to the window, it will be like
window.a
But in test2 this will refer to the obj object.
Related
why this logs 1 and not 2 ? i am trying to pass this scope to initData function but no success. after running init i should trigger iniData but this should refer to the object itself not to a new scope
let startFunction = function (){
let initData = () => {
this.x = 2
}
return {
x:1,
init:initData.bind(this)
};
};
obj=startFunction()
obj.init();
console.log(obj.x); // should be 2
update:
let startFunction = function (){
let initData = function(){
this.x = 2
}
return {
x:1,
init:initData
};
};
obj=startFunction()
obj.init();
console.log(obj.x); // should be 2
and why this works ? shouldn't the function create a new scope ?
There are two issues here. The first issue is that arrow functions are immutably bound to their execution context. Function.prototype.bind has no effect on an arrow function. The second issue here is what this refers to when you call startFunction. When you invoke a function freely, without a binding to a particular object, this refers to the object in which the function is invoked. So this refers to the global object in initData permanently.
So let's think about the value of obj and the global object's x value after each line.
After obj=startFunction:
// global x is undefined
// obj
{
x: 1,
init: initData // with the same binding to the global object
}
After obj.init(), initData sets the global object's x value to 2:
// global x is 2
// obj
{
x: 1,
init: initData // with the same binding to the global object
}
Problem you are facing is the x in the object has nothing to do with the this.x that is being assigned in the init method. You need to set an object and in the init code adjust that object.
let startFunction = function() {
const initData = () => {
data.x = 2
};
var data = {
x: 1,
init: initData,
};
return data;
};
const obj = startFunction()
obj.init();
console.log(obj.x);
Better solution, use a proper class.
class MyClass {
x = 1;
init() {
this.x = 2;
}
}
const obj = new MyClass();
obj.init();
console.log(obj.x);
class MyClass2 {
x = 1;
constructor() {
this.x = 2;
}
}
const obj2 = new MyClass2();
console.log(obj2.x);
Why the arrow function returned in the following example doesn't prints undefined
let obj = {
a: "88",
c: () => {
console.log(this.a);
},
d: function() {
return () => {
console.log(this.a);
}
}
}
let ob = {
a: 99
}
let t = obj.d()
t(); // its printing 88 not undefined why
d was created with a function expression
Therefore when you call obj.d() the value of this is the same as the value of obj.
d returns an arrow function.
Arrow functions have lexical this so it uses this from d which was the same as obj
this.a is therefore the same as obj.a which is "88"
Because when you do let t = obj.d(), it will return you a function that will be saved in t
t = () => {
console.log(this.a);
}
Now talking about this.a, here this will the obj and value of a in obj is 88 do that is the reason 88 is printed
I am getting an issue in the below code:
let a = 13;
function printA() {
let a = 19;
console.log(this.a);
}
let obj = {
a: 10,
fun: function() {
console.log(this.a);
}
};
let obj2 = {
a: 20
};
let x = obj.fun;
x();
can anybody tell why it is printing undefined ?
It prints 13 when we remove let from let a = 13
There is no a for your x to fetch, that is why you get undefined.
let obj = {
a: 10,
fun: function () {
console.log(this.a);
}
};
let x = obj.fun;
x();
Your x is pointing to a function as obj.fun. But there is no obj.fun.x exist, so it will result undefined.
Try the following:
let obj = {
a: 10,
fun: function () {
console.log(this.a);
}
};
let x = obj;
x.fun();
or
let obj = {
fun: function () {
this.a = 10;
console.log(this.a);
}
};
let x = obj.fun;
x();
They both will result 10 as output.
These two example both have an x property under the x.
NOTE: By making a let a = 10 under the fun function will not give you result of this.a is because such declaration works like a private parameter declaration in C/JAVA etc.
I'm learning JS and am wondering, is there a way to return the function bar() or buz() by without returning foo()? For example, if I wanted to return the function bar(); to get 2, could I do that? Would it be something like foo().bar(); ?
// Nested Scopes
function foo() { // can only access itself
var a = 1;
function bar() { // access to foo(), not buz()
var b = 2;
function buz() { // access to bar() and foo()
var c = 3;
console.log(a, b, c); // 1, 2, 3
}
buz();
console.log(a, b); // 1, 2
}
bar();
console.log(a); // 1
}
foo(); // 1
Certainly. You can return an object at each stage which holds the function, or you can return the function itself. This utilizes what's called a closure.
function foo() {
var a = 1;
function bar() {
var b = 2;
function buz() {
var c = 3;
console.log(a, b, c);
}
console.log(a, b);
return { buz: buz };
}
console.log(a);
return { bar: bar };
}
foo().bar().buz();
You can do this, but it’s quite over-complicated.
The basic syntax is:
foo().bar().buz();
Where-ever you add another () after an existing one, it’ll print that level out. See the snippet for examples.
// Nested Scopes
function foo() { // can only access itself
var a = 1;
function bar() { // access to foo(), not buz()
var b = 2;
function buz() { // access to bar() and foo()
var c = 3;
return (function() {
console.log(a, b, c);
});
}
return (function() {
var tmp = function() {
console.log(a, b);
return {
buz: buz
};
};
tmp.buz = buz;
return tmp;
})();
}
return (function() {
var tmp = function() {
console.log(a);
return {
bar: bar
};
};
tmp.bar = bar;
return tmp;
})();
}
foo().bar().buz(); // (nothing)
foo().bar()().buz(); // 1, 2
foo()().bar()().buz(); // 1 // 1, 2
foo()().bar().buz()(); // 1 // 1, 2, 3
foo()().bar()().buz()(); // 1 // 1, 2 // 1, 2, 3
This kind of abuses the fact that you can assign properties to anything in JavaScript, including functions.
foo is a function that refers to the outer foo.
foo() is another function that refers to that inner tmp which has a bar property that refers to the inner bar function.
foo()() actually calls that inner tmp function but still leaves you with an object that has a bar property that again refers to the inner bar function.
This approach is basically the same for bar.
For buz, however, (something).buz() is just a function, without any extra properties and (something).buz()() doesn’t return anything, because that’s the final level.
you do this more like setting a variable.
var foo = {
bar: function() {
return 3;
}
}
console.log(foo.bar());
let o = {
x: 1,
foo() {
setTimeout(()=>
console.log(this.x),
100);
}
}
o.foo();
This prints out 1 after 100ms.
Is this because it is equivalent to the following, meaning that the lexical this binding of arrow functions works?
let o = new (function Object() {
this.x = 1;
this.foo = ()=> console.log(this.x);
});
o.foo();
Is this because it is equivalent to the following, meaning that the lexical this binding of arrow functions works?
No, it's much simpler than that. It's equivalent to
var o = {
x: 1,
foo: function() {
setTimeout(()=>
console.log(this.x),
100);
}
};
o.foo();
and with the arrow function converted:
var o = {
x: 1,
foo: function() {
var self = this;
setTimeout(function() {
console.log(self.x)
}, 100);
}
};
o.foo();
Since you are calling o.foo(), this inside foo refers to o. Because an arrow function's this is subject to lexical scope, it access foo's this.