I have some method of an object assigned by a decorator (that's where the function f, and ms are taken from).
function() {
setTimeout(() => f.apply(this, arguments), ms);
};
'this' refers here to the object. But 'this' of setTimeout is window, not that object. If 'this' of an arrow function is taken lexically, then how come it's not taken from setTimeout? After all, in the following code:
let user = {
firstName: "Ilya",
sayHi() {
let arrow = () => alert(this.firstName);
arrow();
}
};
user.sayHi(); // Ilya
'this' is taken from the function above. So if that function is setTimeout in the first situation why aren't both situations the same? I thought it might have had something to do with the function being passed as argument in one case, and in the other one as a local variable, but wouldn't this come down to the same in lexical environments?
Why is there a difference?
Besides, to test this out:
let obj = {name : "Jeff"};
let obj2 = {name : "Bart", fun2 : function(fun){fun();}};
obj.name2 = obj2.fun2(() => alert(this.name));
but now I don't get "Bart" alerted, but an empty string. When I replace "name" with length, I just get 0, the 'this' refers to the window.
Why doesn't this work as intended?
If 'this' of an arrow function is taken lexically, then how come it's not taken from setTimeout?
Lexical means that the scope is taken from where the function is declared, not where it is passed to.
Inside a function, the value of this depends on how the function is called.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
function f1() {
return this;
}
// In a browser:
f1() === window; // true
In your function you have passed the window object to the setTimeout.
If you alter you function and pass just arguments you will get the object:
function f() {
console.log(this);
};
function a (){
setTimeout(() => f.apply([1]), 1000); // here this = [1]
}
a(); // Array [1]
Related
Why is the value of this in first example: this: myObject and document/window in the second example? If this is defined/evaluated when the function is called, then I dont understand it.
myObject = {
myMethod: function () {
helperObject.doSomethingAsync('superCool', () => {
console.log(this); // this === myObject
});
},
};
const reusabledCallback = () => {
console.log(this); // this === window or global object
};
myObject = {
myMethod: function () {
helperObject.doSomethingAsync('superCool', reusabledCallback);
},
};
this in an arrow function is the same this as the one in the outer scope where the function is defined.
this in a function declared with the keyword function is the object on which the function is being called.
this in the global scope is the window object (or the relevant global object)
In your first code, the arrow function containing this is defined inside a function, so this is whatever called that function (myObject in your case).
In your second code, the arrow function containing this is defined in the global scope, so this is the global object (window).
Both assignment are different. Is there any difference between both of them or both are equal?
First
onClick(){
return (
<div></div>
)
}
Second
const onClick= ()=> {
return(
<div></div>
)
}
ES5 Functions
This type of function doesn't bind with the current context you need to bind it manually, if we do not bind the function with this then the function will find its binding by itself while executing the function according to the execution context.
this.onClick = this.onClick.bind(this);
onClick() {
return <div></div>;
}
ES6 Functions
Simply known as arrow functions, in arrow function there is no binding of this so no effect of this keyword according to the execution context
onClick = () => {
return <div></div>;
}
How Execution Context Effect?
Es5 function behave differently when executed if the function is bounded with any other instance(object) then the this refer to that instance if there is no binding then the this keyword refers to its parent scope.
The setTimeout executed in the global execution context the callback function es5Function which is not bound to any instance, the this keyword in the function will refer to its parent scope which is in our case window
<script>
window.name = "Global Scope";
function App() {
this.name = "App Scope";
let es5Function = function () {
console.log("I am Es5 function I am in the " + this.name);
};
let es5FunctionWithBinding = function () {
console.log(
"I am Es5 function binded with THIS, I am in the " + this.name
);
}.bind(this);
let es6Function = () => {
console.log("I am Es6 function I am in the " + this.name);
};
return [es5Function, es5FunctionWithBinding, es6Function];
}
const [es5Function, es5FunctionWithBinding, es6Function] = new App();
setTimeout(es5Function, 1000);
setTimeout(es5FunctionWithBinding, 1000);
setTimeout(es6Function, 1000);
</script>
Update 2022 A nice discussion with Umair Gilani at khaleef technologies
Using as Function Constructor
One more simple difference is we can not use arrow functions as a function constructor
The question is why?
When we create an object using function constructor (with new keyword) then the function returns the this keyword by default which refers to a new memory location every time.
So simple conclusion
Es5 function has it's own this when using it with new keyword so it returns it by default
Es6 arrow function throw an error [function name] is not a constructor ( because arrow function doesn’t has its own this)
<script>
function Es5(name) {
this.name = name;
// by default it will return this when using with `new` keyword
}
const Es6 = (name) => {
this.name = name; // here this refers to global scope which is window
};
let es5Instance = new Es5("MUHAMMAD ILYAS");
console.log("Es5 instance => Name:", es5Instance.name);
try {
let es6Instance = new Es6("jsfit");
} catch (e) {
console.log("Es6 with new keyword => ERROR:", e.message);
}
let es6InstanceWithoutNewKeyword = Es6("jsfit");
// es6InstanceWithoutNewKeyword will be Undefined because nothing was returned from Es6 function
console.log("ES6 without new keyword: ", es6InstanceWithoutNewKeyword);
// I am in the global scope so here `this` refers to `window` so both will result the `name` exactly the same
console.log("Global scope: ", this.name, "or", window.name);
</script>
What is the difference in rendering from a arrow function and a
function?
There is no difference at all.
Arrow functions differ from regular functions in how they handle this. There are other differences as well but difference related to handling of this is the most significant one.
Not related to your question but you should know that first onClick function cannot be used inside functional components unless function keyword is written before the function name and second onClick function cannot be used inside class components unless const keyword is removed.
Difference is You can change the elements of a constant but you cannot reassign the constant
Here I have copied code snippet from MDN : https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind
function LateBloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 1000);
};
LateBloomer.prototype.declare = function() {
console.log('I am a beautiful flower with ' +
this.petalCount + ' petals!');
};
var flower = new LateBloomer();
flower.bloom();
// after 1 second, triggers the 'declare' method
The most confusing part is : window.setTimeout(this.declare.bind(this), 1000);
I understand how this works and this inside settimeout is always bound to global object.I know there can be var self or var that inside bloom function.
There are two this in that line but which this refers to what and how that works is totally confusing.
How works?
First of all read this article, which offers a very nice explanation about how this works.
.bind(this, args) just helps you to pass your this context inside your function (because inside it in your example by default this is undefined or refers to window).
Also bind is a nice alternative to this:
// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
var self = this;
window.setTimeout(self.declare, 1000);
};
And as the last point in es6 you can do it in this way:
window.setTimeout(() => {
//do some stuff
}, 1000);
instead of
window.setTimeout(function () {
//do some stuff
}.bind(this), 1000);
this allow you to not think about this.
MSDN defines Function.prototype.bind() as,
The bind() method creates a new function that, when called, has its
this keyword set to the provided value, with a given sequence of
arguments preceding any provided when the new function is called.
By using .bind(this) we are passing this to the function declare
See this snippet.
function LateBloomer() {
console.log(this.constructor);
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 1000);
};
LateBloomer.prototype.undefinedbloom = function() {
window.setTimeout(this.declare, 1000);
};
LateBloomer.prototype.declare = function() {
console.log(this.constructor);
console.log('I am a beautiful flower with ' +
this.petalCount + ' petals!');
};
var flower = new LateBloomer();
flower.bloom();
flower.undefinedbloom();
In the function undefinedbloom we are just calling the declare function. So the object will be the window object. It doesn't have property petalCount so its undefined.
In the function bloom we are binding the this of LateBloomer to the declare function by which we will have access to the LateBloomer's object petalCount.
this in JavaScript is a very difficult to fathom at first.
MDN Link: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/this
function LateBloomer() {
this.name = 'triven'; //simplified property
}
// Some thoughts we discuss main requirement.
LateBloomer.prototype.bloom = function() {
window.setTimeout(function() {console.log(this);}, 1000); //Logs window: We all know that keyword this INSIDE CALLBACK
//function refers to Window [Comment 1]
//window.setTimeout(console.log(this), 1000); /Attentions: Here it is very easy to MISUNDERSTAND
//that keyword this is inside setTimeout and it should refer to window.
//Please note that here keyword this is not INSIDE CALLBACK function so here
//keyword this will refer to object on which its wrapper function is
//executed(in our case flower). [Comment 2]
};
//The requirement: We need to call .bloom and it should log name after 1 second.
LateBloomer.prototype.bloom = function() {
//here keyword this refers to object
//window.setTimeout(function() {console.log(this);}, 1000); //But inside callback keyword this refers to window.
};
//We need some way to access object inside call back function so that its name can be accessed after 1 sec.
//step 1; Taking out anonymous function and adding it as a prototype property
LateBloomer.prototype.bloom = function() {
//window.setTimeout(this.callback, 1000); //Note: Keyword this is not inside callback so
//it is referring to object (not window). We can access newly
//defined function on the object. Also keyword this placed inside callback
//function(below) will still refer to window.
};
LateBloomer.prototype.callback = function() {console.log(this.name);}
//step 2; bringing .bind into picture.
//Definition of .bind as per MDN : The bind() method creates a new function
//that, when called, has its this keyword set to the provided value
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.callback.bind(this), 1000); // Okay now we are now invoking .callback method on the object and
//passing the same object to bind.
// The keyword this inside newly return function (as a result of bind) will now refer to object
// we passed as argument to bind and we should not be able to access name property of our object.
// Note : Here both this keywords refers to same object ie on which which are calling .bloom.
//Note : we are no longer using passing callback function defined below. Instead we are now passing
// and exact copy of it but configuring it in such a way that keyword this start refering to object we passed.
};
LateBloomer.prototype.callback = function() {console.log(this.name);}
function wrap(func) {
console.log('0', this)
return function x() {
console.log('1', this)
func()
return function z() {
console.log('3', this)
}
}
}
var obj = {
x: 5,
test: wrap(function y() {
console.log('2', this)
})
}
obj.test()()
The code above logs
// 0 Window
// 1 Object
// 2 Window
// 3 Window
I'm having trouble understanding what dictates what the value of this should be.
// 0 Window makes sense because this is when wrap is first called, and at this point its value this should not be set to obj
// 1 Object makes sense obj.test is now equal to function x(), which properly logs this as obj
// 2 Window I'm not sure why this happens. Why does the value of this not propagate to func()? I thought this was supposed to refer to the owner of the function. Does this mean that even though function y() was created inside obj it was somehow hoisted to the window?
// 3 Window Likewise with function z() why was the value of this not passed down from function x(). Isn't the value of this supposed to propagate there?
The 'this' binding is very confusing. However, if you remember these following rules, it will be easier to understand. According to Javascript documents, there are four rules for 'this' binds in these orders:
new operator
explicit or hard binding via call or apply methods
implicit binding with containing object, like a method of an object
default (global)
From your scripts, only rules #3 and #4 apply because there are no new operators and call or apply methods.
So the explanations are:
// 0 Window - rule #4 default (global)
// 1 Object - rule #3 implicit binding with containing object, like a method of an object, obj.test in your case
// 2 Window - rule #4 default (global)
// 3 Window - rule #4 default (global)
Following, the mostly accurate guidance of this article, in order, the function calls desugar to
wrap.call(window, function() {})
obj.test.call(obj)
y.call(window)
z.call(window)
The thing to keep in mind is that this does not propagate through function declarations. The value of this depends entirely upon how the function called.
The reason I was confused was because I had gotten a bit too used to arrow functions, which preserve the value of this for you.
function wrap(func) {
return () => {
console.log(this)
return () => {
console.log(this)
func()
return () => console.log(this)
}
}
}
this desugars to
function wrap(func) {
var _this = this;
return function () {
console.log(_this);
return function () {
console.log(_this);
func()
return function () {
return console.log(_this);
};
};
};
}
and shows that you have to explicitly pass down the value of this. Though even with arrow functions, it's important to note the call to func will not preserve the value of this. I would need to do func.call(this) in order to do that.
Is there a way to get the Function object, while the function is executing?
I am assigning properties to my function, and want to access them. "this" doesn't help. Something like:
a.b=function(){...code...};
a.b.c=100;
I want to access a.b.c from the code in the function, without knowing its own name. "this" refers to a. How can get b?
I tried binding the function to his own object, but I couldn't.
Thank you.
I'm adding this example, I have to repeat after several different "theString" and "someSpecificValues":
Object.defineProperty(theObject, theString, {get: function(...){...}.bind(theObject, someSpecificValues), configurable: true});
You can use a named function expression for this:
var a = {};
a.b = function myFunc() {
console.log(myFunc.c);
};
a.b.c = 100;
a.b();
It allows code inside the function to access the function itself, but does not add the identifier to the enclosing scope.
Edit: Here is a more elaborate example of how the name myFunc only exists within the function:
var a = {};
a.b = function myFunc() {
console.log(myFunc.c);
};
a.b.c = 100;
a.d = function myFunc() {
console.log(myFunc.c);
};
a.d.c = 300;
a.b(); // logs 100
a.d(); // logs 300
console.log(typeof myFunc); // logs "undefined"
// create a myFunc variable
var myFunc = function() {
console.log("nooooooo!!!!");
};
a.b(); // STILL logs 100. the myFunc variable in this scope
// has no effect on the myFunc name that a.b uses
function callFunc(theFunc) {
theFunc();
}
callFunc(a.d); // STILL logs 300
// ===========================
function returnNamedFunction () {
return function myFunc() {
console.log(myFunc.c);
};
}
var iGotAFunction = returnNamedFunction();
iGotAFunction.c = 700;
iGotAFunction(); // logs 700
In the case when you cannot use a named function expression, e.g. when you are using .bind() on it, then an IIFE will suffice most of the time:
var myObj = {};
myObj.theFunc = (function () {
var f = function (arg1, arg2) {
console.log(this.theProp);
console.log(arg1);
console.log(arg2);
console.log(f.lista);
}.bind(myObj, "A!");
return f;
})();
myObj.theProp = "B!";
myObj.theFunc.lista = [1, 2, 3];
myObj.theFunc("C!");
There are two ways to get current function.
One is "almost deprecated" usage of arguments.callee. In function body it always refers to this function.
var a = {};
a.b = function () {
console.log(arguments.callee.c);
};
a.b.c = 100;
a.b();
arguments.callee is forbidden in strict mode. Reference.
The second one is using named function expression as JLRishe pointed.
arguments.callee pros and cons
Advantages:
it can be safely used with bound functions (arguments.callee refers to bound function)
it can be used with functions created using new Function
Disadvantages:
it can slow your program due to disabling certain optimisations
it's considered as almost deprecated
it can't be used in strict mode
Named function expression pros and cons
Advantages:
it's faster than arguments.callee
it's easier to understand how it works
Disadvantages:
it won't work as expected with bound functions (functionName will refer to original function, not bound one)
it can't be used in functions created with new Function