understanding the "this" binding - javascript

Im reading "Eloquent Javascript" book and I'm in the chapter "The secret life of objects".
And the author says:
"since each function has it's own bindings, whose value depends on
they way it is called, you cannot refer to the this of the wrapping
scope in a regular function defined with the function keyword.
i did not understand what does he mean by "wrapping scope", can you please explain and provide a simple example?

Wrapping scope of your function would be the scope where the function is defined.
e.g.
function outer() {
var outerThis = this;
return function inner() {
console.log(outerThis, this);
}
}
Here, inner function has wrapping scope = scope of outer. And, the inner function doesn't have access to the outer's this which is why we need to store it in a variable outerThis if we want to use it.
var innerFunction = outer.call({});
innerFunction();
If you do above on chrome console, This will print:
{}, // Caller of outer() (it was bound)
Window // Caller of inner()

Here is an example of how the use of "function" keyword will produce a function that does not have the same meaning to "this" as the containing scope has. You can overcome this by using an arrow function.
See also: https://medium.com/better-programming/difference-between-regular-functions-and-arrow-functions-f65639aba256
const container = {
name: "Bob",
sayName: function() {
console.log('say name root:', this.name);
const nestedWithFunctionKeyword = function() {
// Notice here that introducing "function" ruins the "this" reference. It no longer is referring to "container".
console.log('say name function:', this.name);
};
nestedWithFunctionKeyword();
// But we can re-bind "this" if we want.
nestedWithFunctionKeyword.call(this);
const nestedWithArrowSyntax = () => {
console.log('say name with arrow:', this.name);
};
nestedWithArrowSyntax();
},
};
container.sayName();
console.log('-----------------');
// Now lets look how how "the way you call the function" matters. Here we do not call the function within the context of "container" anymore, so the results change.
const sayNameRef = container.sayName;
sayNameRef();

this keyword refers to the object it belongs to, for example:
function diner(order) {
this.order = order;
this.table = 'TABLE 1';
this.eatHere = eatHere
this.goOutside = goOutside
function eatHere() {
// adding () instead of a function
// will use the scope of the object it self
setTimeout(() => {
console.log(`EAT HERE: eating ${this.order} at ${this.table}`);
}, 200);
}
function goOutside() {
// adding a new function scope inside the function
// will go outside the current object's scope
setTimeout(function () {
console.log(`EAT OUTSIDE: eating ${this.order} at ${this.table}`);
}, 200);
}
}
let obj = new diner("soup");
obj.eatHere(); // this order will be defined
obj.goOutside(); // this order will be undefined

Related

AngularJs Service function- this()

I'm learning about angularjs and I keep noticing when a function is declared, most people usually make "this" into a var before modifying it. Why is that?
Code snippet below:
function NameService() {
var self = this; **THIS BLOCK. WHY??**
//getName returns a promise which when
//fulfilled returns the name.
self.getName = function() {
return $http.get('/api/my/name');
};
}
And at the bottom, the example uses self.getName. Why not just directly call this.getName?
Thanks
This is just a pattern that you can use. Generally it helps avoiding collisions of the 'this' keyword which is very common in the javascript 'world'.
Also helps with readability, so you can easier read your code.
Check out this example, where you can easily distinguish the public functions of the service and the local/private ones:
function NameService() {
var self = this; **THIS BLOCK. WHY??**
self.getName = getName;
self.setName = setName;
//getName returns a promise which when
//fulfilled returns the name.
function getName() {
return $http.get('/api/my/name');
};
function setName(){
//blablabla
}
function justAHelperFunction(){
//helper function, kind of inner function, a private function
}
}
In javascript this refers to the current object and the value of this in say a method depends how the function is invoked. When you pass a callback to a function call the context of this gets changed and inside the callback definition this doesn't refer to the object that has the method which further called the function with callback.
var person = {
firstName: 'John',
lastName: 'Doe',
printFullName: function () {
setTimeout(function () {
// here this doesn't point to the person object anymore
// as the callback passed to setTimeout was invoked by global window object
// so this points to window
console.log(this.firstName + ' ' + this.lastName);
}, 100)
}
}
To fix the above scenario where you expect this to be person you make an alias of the context capturing the reference in another variable. Here's the correct version of above method.
printFullName: function () {
var self = this;
// till now self == this
setTimeout(function () {
// here self still points to person whereas this is now pointing to window
console.log(self.firstName + ' ' + self.lastName);
}, 100)
}

What does "this" refer to in arrow functions in ES6?

I've read in several places that the key difference is that this is lexically bound in arrow functions. That's all well and good, but I don't actually know what that means.
I know it means it's unique within the confines of the braces defining the function's body, but I couldn't actually tell you the output of the following code, because I have no idea what this is referring to, unless it's referring to the fat arrow function itself....which doesn't seem useful.
var testFunction = () => {
console.log(this)
};
testFunction();
Arrow functions capture the this value of the enclosing context
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| properly refers to the person object
}, 1000);
}
var p = new Person();
So, to directly answer your question, this inside your arrow function would have the same value as it did right before the arrow function was assigned.
In order to provide the big picture I'm going to explain both, dynamic and lexical binding.
Dynamic Name Binding
this refers to the object the method is called on. This is a regularly to be read sentence on SO. But it is still only a phrase, pretty abstract. Is there a corresponding code pattern to this sentence?
Yes there is:
const o = {
m() { console.log(this) }
}
// the important patterns: applying methods
o.m(); // logs o
o["m"](); // logs o
m is a method because it relies on this. o.m() or o["m"]() means m is applied to o. These patterns are the Javascript translation to our famous phrase.
There is another important code pattern that you should pay attention to:
"use strict";
const o = {
m() { console.log(this) }
}
// m is passed to f as a callback
function f(m) { m() }
// another important pattern: passing methods
f(o.m); // logs undefined
f(o["m"]); // logs undefined
It is very similar to the previous pattern, only the parenthesis are missing. But the consequences are considerable: When you pass m to the function f, you pull outm of its object/context o. It is uprooted now and this refers to nothing (strict mode assumed).
Lexical (or Static) Name Binding
Arrow functions don't have their own this/super/arguments binding. They inherit them from their parent lexical scope:
const toString = Object.prototype.toString;
const o = {
foo: () => console.log("window", toString.call(this)),
bar() {
const baz = () => console.log("o", toString.call(this));
baz();
}
}
o.foo() // logs window [object Window]
o.bar() // logs o [object Object]
Apart from the global scope (Window in browsers) only functions are able to form a scope in Javascript (and {} blocks in ES2015). When the o.foo arrow function is called there is no surrounding function from which baz could inherit its this. Consequently it captures the this binding of the global scope which is bound to the Window object.
When baz is invoked by o.bar, the arrow function is surrounded by o.bar (o.bar forms its parent lexical scope) and can inherit o.bar's this binding. o.bar was called on o and thus its this is bound to o.
Hope this code show could give you clearer idea. Basically, 'this' in arrow function is the current context version of 'this'. See the code:
// 'this' in normal function & arrow function
var this1 = {
number: 123,
logFunction: function () { console.log(this); },
logArrow: () => console.log(this)
};
this1.logFunction(); // Object { number: 123}
this1.logArrow(); // Window
Arrow function this is pointing to the surrounding parent in Es6, means it doesn't scope like anonymous functions in ES5...
It's very useful way to avoid assigning var self to this which is widely used in ES5...
Look at the example below, assigning a function inside an object:
var checkThis = {
normalFunction: function () { console.log(this); },
arrowFunction: () => console.log(this)
};
checkThis.normalFunction(); //Object {}
checkThis.arrowFunction(); //Window {external: Object, chrome: Object, document: document, tmpDebug: "", j: 0…}
You can try to understand it by following the way below
// whatever here it is, function or fat arrow or literally object declare
// in short, a pair of curly braces should be appeared here, eg:
function f() {
// the 'this' here is the 'this' in fat arrow function below, they are
// bind together right here
// if 'this' is meaningful here, eg. this === awesomeObject is true
console.log(this) // [object awesomeObject]
let a = (...param) => {
// 'this is meaningful here too.
console.log(this) // [object awesomeObject]
}
so 'this' in fat arrow function is not bound, means you can not make anything bind to 'this' here, .apply won't, .call won't, .bind won't. 'this' in fat arrow function is bound when you write down the code text in your text editor. 'this' in fat arrow function is literally meaningful here. What your code write here in text editor is what your app run there in repl. What 'this' bound in fat arror will never change unless you change it in text editor.
Sorry for my pool English...
Arrow function never binds with this keyword
var env = "globalOutside";
var checkThis = {env: "insideNewObject", arrowFunc: () => {
console.log("environment: ", this.env);
} }
checkThis.arrowFunc() // expected answer is environment: globalOutside
// Now General function
var env = "globalOutside";
var checkThis = {env: "insideNewObject", generalFunc: function() {
console.log("environment: ", this.env);
} }
checkThis.generalFunc() // expected answer is enviroment: insideNewObject
// Hence proving that arrow function never binds with 'this'
this will always refer to the global object when used inside an arrow function. Use the regular function declaration to refer to the local object. Also, you can use the object name as the context (object.method, not this.method) for it to refer to the local object instead of the global(window).
In another example, if you click the age button below
<script>
var person = {
firstName: 'John',
surname: 'Jones',
dob: new Date('1990-01-01'),
isMarried: false,
age: function() {
return new Date().getFullYear() - this.dob.getFullYear();
}
};
var person2 = {
firstName: 'John',
surname: 'Jones',
dob: new Date('1990-01-01'),
isMarried: false,
age: () => {
return new Date().getFullYear() - this.dob.getFullYear();
}
};
</script>
<input type=button onClick="alert(person2.age());" value="Age">
it will throw an exception like this
×JavaScript error: Uncaught TypeError: Cannot read property
'getFullYear' of undefined on line 18
But if you change person2's this line
return new Date().getFullYear() - this.dob.getFullYear();
to
return new Date().getFullYear() - person2.dob.getFullYear();
it will work because this scope has changed in person2
Differences between arrow functions to regular functions: (taken from w3schools)
With arrow functions there are no binding of this.
In regular functions the this keyword represented the object that called the function, which could be the window, the document, a button or whatever.
With arrow functions the this keyword always represents the object that defined the arrow function.
// Regular Function:
hello = function() {
document.getElementById("demo").innerHTML += this;
}
// The window object calls the function:
window.addEventListener("load", hello);
// A button object calls the function:
document.getElementById("btn").addEventListener("click", hello);
// -------------------------------------------
// Arrow function
hello2 = () => {
document.getElementById("demo2").innerHTML += this;
}
// The window object calls the function:
window.addEventListener("load", hello2);
// A button object calls the function:
document.getElementById("btn2").addEventListener("click", hello2);
<p><i>With a regular function this represents the <b>object that calls the function</b>:</i></p>
<button id='btn'>click me regular function</button>
<p id="demo">Regular function: </p>
<hr>
<p><i>With arrow function this represents the <b>owner of the function(=the window object)</b>:</i></p>
<button id='btn2'>click me arrow function</button>
<p id="demo2">Arrow function: </p>
A related issue:
Came from - Why can't I access `this` within an arrow function?
We know below from here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Does not have its own bindings to this or super, and should not be used as methods.
Arrow functions establish "this" based on the scope the Arrow function is defined within.
Had a issue with this using arrow functions, so created a class (can be function), and class variable is accessed in arrow function, thereby achieved smaller functions using arrow functions without function keyword:
class MyClassOrFunction {
values = [];
size = () => this.values.length;
isEmpty = () => this.size() === 0;
}
let obj = new MyClassOrFunction();
obj.size(); // function call here
You can also have a getter like this, that does not have function keyword, but a bit longer due to return statement, also can access other member functions:
class MyClassOrFunction {
values = [];
size = () => this.values.length;
get length() { return this.size(); }
}
let obj = new MyClassOrFunction();
obj.length; // NOTE: no function call here

Is this an example of a javascript closure

Still feel my understanding of Javascript closure is a little woolly at times and I would like to know if the code below represents closure in action...
function StateManager () {
var self = this;
this.state = null;
$(document).on("internal_StateManager_getState", function () {
return self.state;
});
$(document).on("internal_StateManager_setState", function (e, p) {
if ( p && p.state ) {
self.state = p.state
}
return self.state;
});
};
new StateManager();
alert( $(document).triggerHandler("internal_StateManager_setState", { "state": 88 }) );
Is it accurate to say that this demonstrates closure because the state and self variables are accessable via the events? Thanks for any input!
In the code in the question, the StateManager function does not create a closure, as it doesn't reference "free" variables from outside it's lexical scope.
However the jQuery callbacks are in fact closures, as they do reference the self variable which is defined outside the lexical scope of the callback functions.
A closure is, from MDN
Closures are functions that refer to independent (free) variables.
In other words, the function defined in the closure 'remembers' the environment in which it was created.
A simple example would be something like
function something() {
var test = "Hello Kitty"; // "test" is a local variable created in this scope
function otherFunc() { // this is an inner function, a closure
alert( test ); // uses variable declared in the parent function
}
}
That's about as simple as closure gets, it's just a function inside another function that uses variables outside it's lexical scope.
Another familiar example would be
$(document).ready(function() { // creates outer scope
var data = 'important stuff';
$('.elems').on('click', function() { // this is a closure
$(this).text( data ); // uses variable outside it's scope
});
});

Scope clarification in javascript [duplicate]

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Explanation asked about the value of 'this' in Javascript [duplicate]
(2 answers)
Closed 8 years ago.
Simple question. Why do we have set that = this? If we dont, we are in the global scope...but why?
var myObj = {
specialFunction: function () {
},
anotherSpecialFunction: function () {
},
getAsyncData: function (cb) {
cb();
},
render: function () {
var that = this;
this.getAsyncData(function () {
// this now refers to global scope....why?
that.specialFunction();
that.anotherSpecialFunction();
});
}
};
myObj.render();
Writing that = this doesn't change the scope. The way the anonymous function is called will always end up with this being global object,* because that's exactly what the spec says should happen. Using that = this is just a workaround.
You could make this always point to myObj by using Function.call:
var myObj = {
specialFunction: function () {
},
getAsyncData: function (cb) {
cb.apply(this);
},
render: function () {
this.getAsyncData(function () {
this.specialFunction();
});
}
};
and/or using Function.bind:
var myObj = {
specialFunction: function () {
},
getAsyncData: function (cb) {
cb();
},
render: function () {
function callback() {
this.specialFunction();
}
this.getAsyncData(callback.bind(this));
}
};
* Unless you're in strict mode, in which case this is undefined.
take a look at the this keyword in JavaScript and how it works. I’m sure we’ve all come across this issue:
$("myLink").on("click", function() {
console.log(this); //points to myLink (as expected)
$.ajax({
//ajax set up
success: function() {
console.log(this); //points to the global object. Huh?
}
});
});
this is a variable that is automatically set for you when a function is invoked. The value it’s given depends on how a function is invoked. In JavaScript we have a few main ways of invoking functions. I wont talk about them all today, but just the three ways most people use them; either when a function is called as a method, or on it’s own, or as an event handler. Depending on how a function is invoked, this is set differently:
function foo() {
console.log(this); //global object
};
myapp = {};
myapp.foo = function() {
console.log(this); //points to myapp object
}
var link = document.getElementById("myId");
link.addEventListener("click", function() {
console.log(this); //points to link
}, false);
Doing $("myLink").on("click", function() {}) means that when the element is clicked, the function is fired. But this function is bound as an event handler, so this is set to the reference to the DOM element myLink. The success method you define within the Ajax request is just a regular function, and as such when it’s invoked, this is set to the global object, as it is when any function that’s not an event handler or an object method is.
$("myLink").on("click", function() {
console.log(this); //points to myLink (as expected)
var _this = this; //store reference
$.ajax({
//ajax set up
success: function() {
console.log(this); //points to the global object. Huh?
console.log(_this); //better!
}
});
});
Source: http://tinyurl.com/melbl92
EDIT: in JavaScript the "this" context depends on how your function is called, example:
function helloWorld()
{
console.log(this);
}
And here two ways to call this function:
new helloWorld(); note that if you call your function in this
way, the context of this will be the context of the function +
prototype, so your console will show this: helloWorld {}
helloWorld(); if you call your function without of the "new",
the context of "this" will be global(Window), so your console will show
this: Window about:home
Ok, with this little explanation i will try to explain now why you
have sometimes to use self/that...
Imagine that you want to use this.name inside this.hello function. Like I said before, the context of "this" depends on how your function is called, so if you want to ensure that this.name inside of this.hello function refer to this.name outside is recommended that you use self/that to avoid what happens bellow
function helloWorld(){
var self = this;//or that = this
this.name = "YourName"
this.hello = function(){
console.log(this); //the context of "this" here will be: "hello {}"
return this.name; //undefined, because you don't have name attribute inside hello function
}
new this.hello(); //note how hello is called here...
}
var test = new helloWorld();
And here a good explanation about context x scope:
http://ryanmorr.com/understanding-scope-and-context-in-javascript/

Why nested local function binds `this` to window instead of the parent

I was reading some documentation about javascript and stumbled upon the following code example:
var o = {
value: 1,
outer: function () {
var inner = function () {
console.log(this); //bound to global object
};
inner();
}
};
o.outer();
It outputs window.
I cannot figure out why is the this keyword bound to the global object (window) instead of the parent object (outer).
If you want to access outer from inner's scope, you have to pass the outer's this (which is just like passing outer itself) to its local inner function as an argument. So, as expected:
var o = {
value: 1,
outer: function () {
var inner = function (that) {
console.log(that); //bound to global object
};
inner(this);
}
};
o.outer();
outputs outer.
Isn't it a bit of a nonsense that in outer's scope this is bound to the object itself (i.e. outer), while in the inner's scope, which is local to outer, this is re-bound to the global object (i.e. it overrides outer's binding)?
The ECMAScript specs states that when entering the execution context for function code if the «caller provided thisArg» is either null or undefined, then this is bound to the global object.
But the following:
var o = {
outer: function () {
var inner = function () {
console.log('caller is ' + arguments.callee.caller);
};
inner();
}
}
outputs the object outer itself:
caller is function () {
var inner = function () {
console.log('caller is ' + arguments.callee.caller);
};
inner();
}
On a side, but probably relevant, note:
In strict mode the first code snippet outputs undefined instead of window.
This is because this is set when the function is run, not when it's defined.
For example:
var o = {
func: function(){
console.log(this);
}
};
When you call o.func(), you are doing so in the context o, so it works as expected.
Now let's say you do this:
var f = o.func;
f();
This will not work as expected. This is because when you call f(), it doesn't have any context attached to it, so this will be window.
You can fix this by using .call to change the value of this.
var f = o.func;
f.call(o); // sets `this` to `o` when calling it
That's just how it the language works.
Every time a function is called, this will be reset. In a nested (inner) function it does not inherit the value from the enclosing scope the way other (explicitly declared) variables are.
By default this will be set to window, unless the function is invoked as:
myObj.func(arg1, ...) or
func.call(myObj, arg1, ...) or
func.apply(myObj, [arg1, ...])
in which case this will be equal to myObj
A function called any other way, even if it was originally defined as a property of an object (i.e. var func = myObj.func; func() will use window.
There's also a utility function called .bind which wraps a function reference in such a way that you can provide a specific value which will always be used as this:
var myFunc = myObj.func; // obtain reference to func
var bound = myFunc.bind(someOtherObj); // bind it to "someOtherObj"
bound(); // this === someOtherObj
bound.call(myObj) // this still === someOtherObj

Categories

Resources