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
Assuming functions in javascript are actually objects, how can I assign properties to this function object within the function itself.
Below are not working as 'this' keyword is referring to the window object, so 'prop' will be assigned to the window global object not to the function object.
function test() {
this.prop = value;
}
Why 'this' keyword inside global functions is referring to the window object and not referring to the function object itself?
Edit:
My question is different from the duplicate question as I am asking how to assign a property to a global function inside that function, not about the scope of variables.
Reference the function by name:
function test(value) {
test.prop = value;
}
test('hello');
console.log(test.prop); // => "hello"
Short answer: invoke the function via call and pass the intended this as the first argument.
function test(value) {
this.prop = value
}
// 'this' v v value
test.call(test, 10)
console.log(test.prop) // 10
The purpose of call is to explicitly set the this of the invoked function.
Explanation:
For non-strict mode, when the function is invoked without a caller, e.g., test(10), this is implicitly set to the global object, in this case window. In strict mode, it will be undefined.
function test() {
return this
}
console.log(test()) // window (or undefined in strict mode)
Inside of a function, this refers to the caller of the function.
const caller = {
test: function () { return this }
}
console.log(caller.test()) // caller, i.e., { test: function() {...} }
This is true with 'classes' as well (functions invoked with new).
function MyConstructor() {
this.test = function() {
return this
}
}
const instance = new MyConstructor()
console.log(instance.test()) // instance of MyConstructor
Depending on your use case, it may be preferable to use this form:
const myObj = {
test: function(value) {
this.prop = value
}
}
// 'prop' will be set on `myObj` instead of the function.
myObj.test(10)
console.log(myObj) // { prop: 10, test: function(value) {...} }
or a class-like construct:
function MyConstructor(value) {
this.prop = value
}
const instance = new MyConstructor(10)
console.log(instance) // MyConstructor { prop: 10 }
console.log(instance.prop) // 10
In my understanding, it is not until an object invokes a Function that this is actually assigned a value. And the value it is assigned is based exclusively on the object that invokes the Function.
Also, the scope chain rule in JS is LEG.
So, in (strict mode):
function one () {
var a = 2;
function two () {
console.log(a)};
two()
}
one() // output 2
But:
function one () {
var a = 2;
function two () {
console.log(this.a)};
two()
}
one() //output undefined
It was my understandig functions were objects, and in the previous invokation the function object one would be the making the call of two, which translates this.a into one.a. Obviously that is not the case.
Also:
function one () {
var a = 2}
console.log(one.a) //outputs undefined
Any clarification about what is happening would be very appreciated.
Thanks
function one () {
var a = 2;
function two () {
console.log(this.a)};
two()
}
one() //output undefined
Here you are calling both one and two as functions on their own, not as properties of some object (e.g. someObject.one()). This means that this will refer to the global scope (or to undefined if the code is in strict mode). The a property of your global scope is undefined, so that's why you see undefined. Calling two() inside of one() doesn't make it so that this refers to one.
function one () {
var a = 2}
console.log(one.a) //outputs undefined
a is not a property of one. It is a variable inside it. A property of one would look like this.
function one() {
}
one.a = 7;
console.log(one.a);
I think you are treating a regular function as a class object. You only call one() but you do not actually instantiate a new One() object.
Scope and Context are different concepts. Within a JS-Function scope one can address any value that either got assigned inside a function or any value that got assigned outside such a function as long as this function itself is a member of the outer scope. In addition, as long as a function does not create a closure, scope gets created just at a function's call time. Context is addressable too. But unlike scope, context gets evaluated at a functions call time. Thus this is just a placeholder for context that can vary from one time calling a function to another.
function contextAwareMethod(injectedValue) {
"use strict";
var
context = this, // dynamically evaluated.
innerScopeValue = "created at a functions call time";
console.log('dynamically evaluated context : ', context);
console.log('this.contextValue : ', (context && context.value));
console.log('innerScopeValue : ', innerScopeValue);
console.log('injectedValue : ', injectedValue);
}
console.log('"case A"');
contextAwareMethod('argument A');
console.log('\n');
console.log('"case B"');
contextAwareMethod.call({ value: "conext B"});
console.log('\n');
console.log('"case C"');
contextAwareMethod.call({ value: "conext C"}, 'argument C');
console.log('\n');
.as-console-wrapper { max-height: 100%!important; top: 0; }
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
I'm trying to make a class without prototypes. Here is an example:
test = (function() {
this.value = 1;
this.print = function() {
console.log(this.value);
};
return this;
})();
This works perfectly as intended. What I don't understand is this.value inside the this.print function. How does this.print correctly know that any mention of this refers to test and not window? Would any function defined via this.___ = function(){} automatically have this added as a context?
this always1 evaluates to the object upon which the function-object was invoked. It will evaluate to window if it was "invoked upon nothing" (or is a property of window).
(Note that this is not a variable and is thus not closed-over in a closure! This is why sometimes closures are needed to get the "correct" this which is often known by the variable self or that or _this.)
For example:
function f () { return this; }
var a = {f: f}
var b = {f: f}
a.f() === a // true
b.f() === b // true
f() === window // true
An example of using a variable to create a binding to the current (as of when the enclosing function was invoked) this:
test = (function() {
var self = this // <-- variable, which is "closed over"
this.value = 1; // self === this
this.print = function() {
console.log(self.value); // <-- self "names" previous this object
};
return this;
})();
1 This is a little lie. The Function.call and Function.apply functions allow specifying the this context and can be used by "context binding" functions such as Function.bind to eliminate the need for an explicit "self closure" as shown above.