How do I access an object within itself, within another object? - javascript

I know that using the "this" keyword in an object references the object, but what about nested objects?
var mainObj = {
childObj: {
addProperty: function() {
this.message = "HELLO";
}
}
};
mainObj.childObj.addProperty();
From here, how do I access the "this.message" property, both inside and outside the "childObj" object?

The quick answer: within a different method of mainObj, you can use this.childObj.message, and you can use mainObj.childObj.message from the outside:
var mainObj = {
childObj: {
addProperty: function() {
this.message = "HELLO";
}
},
msg() {
return this.childObj.message;
},
};
mainObj.childObj.addProperty();
console.log(mainObj.msg()); // HELLO
console.log(mainObj.childObj.message); // HELLO
Some context on this:
From the MDN documentation:
A function's this keyword behaves a little differently in JavaScript compared to other languages. It also has some differences between strict mode and non-strict mode.
In most cases, the value of this is determined by how a function is called. It can't be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind method to set the value of a function's this regardless of how it's called, and ES2015 introduced arrow functions which don't provide their own this binding (it retains the this value of the enclosing lexical context).
Basically, depending on the context, this might mean different things:
Global context
Outside of any function, this refers to the global object. In a browser that means this === window.
Function context
In a function, the value of this depends on how you call the function, and whether you are using strict mode or not., basically it could point to the global object or inherit the execution context.
When invoking a function as a method of an object, this will be set to the object that owns the method in the invocation:
//'use strict';
window.message = 'wat';
const obj1 = { message: 'hi 1', hi() { return this.message; }};
const obj2 = { message: 'hi 2', hi() { return this.message; }};
// Normal invocation
console.log(obj1.hi())
console.log(obj2.hi())
// As functions:
const obj1Hi = obj1.hi;
console.log(obj1Hi()); // returns wat on non-strict mode!
// enable use strict to see the error thrown by this defaulting to undefined/
// Swap the functions around
obj1.hi = obj2.hi;
obj2.hi = obj1Hi;
console.log(obj1.hi()) // still uses message from obj1
console.log(obj2.hi()) // still uses message from obj2
// You can even do some `bind` magic to force the context on a function:
console.log(obj1Hi.bind(obj1)()); // hi 1
console.log(obj1Hi.bind(obj2)()); // hi 2

Related

What is "this" in an arrow function in JavaScript

I have a question about what the "this" points to in an arrow function:
// run this file in nodejs by: node test_this.js
const obj = {
scope:this,
func1:()=>{return this},
func2:function(){
const fn = ()=>this;
return fn();
}
}
console.log("0",obj.scope); // module.exports
console.log("1",obj.func1()); // module.exports
console.log("2",obj.func2()); //obj
const newFunc2 = obj.func2;
console.log("newFunc2",newFunc2()); //global
As I konw, arrow function has no own "this". The scope determines the "this" once the arrow function is declared, and it will never be changed. But why the console.log("2",obj.func2()); outputs the obj? and why console.log("newFunc2",newFunc2()); print a different result global?
The lexical value of this for your obj declaration is module.exports. That's the value of this when your obj variable is declared.
So, that explains why obj.scope is module.exports because that is the value of this at the time your object is declared and initialized with your code scope:this,
As you seem to already know, the arrow function declaration when called with an object as in obj.func1() does not carry through obj as this. Instead, it uses the lexical version of this (what it was at declaration time). As obj.scope shows, that lexical value of this is module.exports. So, the result of console.log("1",obj.func1()) is module.exports as expected (because func1 is defined as an arrow function.
Then, with obj.func2(), that is declared as a normal function so the value of this inside of func2, when called as obj.func2() will be obj. This is how method function calls like obj.func2() work in Javascript (as long as the function is a normal function definition or method definition, not an arrow function).
Lastly, when you do this:
const newFunc2 = obj.func2;
You are getting a reference to JUST the func2 method, all by itself. You've isolated just the method and it has no association at all with the object any more. So, when you call it like this:
console.log("newFunc2",newFunc2());
The object referenced for obj is completely gone and the this value will be set the same as any plain function call will be. The value of this will be set to undefined if you're running strict mode or to the global value if not running strict mode.
For a bit of a review of how all this works or a reference for the future, see:
The 6 ways the value of this is determined inside a function at execution time.
When you're assigning obj.func2 to newFunc2, the function is copied to the new variable, having no connection with the obj anymore. So when you are calling newFunc2(), it's referring to the window object by this in that scope. Below example demonstrate that obj.func2 when defined, doesn't have any information of className. When we copy the function func2 in the class MyObj, this now refers to the new class, hence you get the log this.className = 'MyObj'
const obj = {
scope:this,
func1:()=>{return this},
func2:function(){
const fn = ()=>this;
console.log(this.className)
return fn();
}
}
class MyObj {
constructor() {
this.className = 'MyObj'
this.obj()
}
obj() {
this.func2 = obj.func2
}
print() {
this.func2()
}
}
var myObj = new MyObj()
myObj.print()
.
The JavaScript this keyword refers to the object it belongs to.
It has different values depending on where it is used:
In a method, this refers to the owner object.
Alone, this refers to the global object.
In a function, this refers to the global object.
In a function, in strict mode, this is undefined.
In an event, this refers to the element that received the event.
Methods like call(), and apply() can refer this to any object.
In strict mode, when used alone, this also refers to the Global object [object Window]
"use strict";
var x = this; // x equals [object Window]

Why doesn't JS always bind `this` to `foo` when foo.fn() is called?

I think JavaScript ES6's arrow functions have two changes:
get rid of the "lost binding issue".
make this not bind to foo when foo.fn() is called.
For (1) above, the following code can illustrate (running inside of Node console):
var peter = {
name: "Peter Pan",
greetLater: function() {
setTimeout(function() {
console.log("Hi my name is", this.name);
}, 0);
}
};
peter.greetLater(); // => Hi my name is undefined
var michael = {
name: "Michael J Fox",
greetLater: function() {
setTimeout(() => {
console.log("Hi my name is", this.name);
}, 0);
}
};
michael.greetLater(); // => Hi my name is Michael J Fox
For (2) above, the following code can illustrate:
var winona = {
name: "Winona Ryder",
greet: function() {
console.log("Hi my name is", this.name);
}
};
winona.greet(); // => Hi my name is Winona Ryder
var demi = {
name: "Demi Moore",
greet: () => {
console.log("Hi my name is", this.name);
}
};
demi.greet(); // => Hi my name is undefined
I can understand (1) is a good thing as it solves the "lost binding" issue. But (2) is like "cutting the binding". It might seem that (2) is to solve the issue of (1), which is to go up the lexical scope to find this, but I think having (1) and not having (2) can co-exist: that is, when foo.fn() is called, the this inside the code of fn() can still refer to foo.
What is wrong with when foo.fn() is called, the this inside the code of fn() can still refer to foo, and when it is "dangling function", as in the SetTimeout() in (1) above, or in the following code:
winonaGreet = winona.greet;
winonaGreet(); // => Hi my name is undefined
then it uses the new behavior of going up the lexical scope to find the this? Isn't this more coherent with everything?
That is, when it is fn() or passed to SetTimeout and stored as fn and later invoked as fn(), then look up the lexical scope, but for foo.fn(), it just make a lot of sense to bind this to foo instead of looking up the lexical scope.
Why would we have 2 new rules, one to keep the binding and one to cut it?
And it seems for (2), the ways we can still call foo.fn() and have this inside of fn() bind to foo is to not use arrow function, or use ES6's class, as in Mozilla's example:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea();
}
// Method
calcArea() {
return this.height * this.width;
}
}
but then, when we have (1), why do we have (2) also? It is like a hybrid of most other languages, where if foo.fn() is called, the this is always bound to foo.
this and Arrow Functions:
Arrow functions, introduced in ES6, provides a concise way to write functions in >JavaScript.
Another significant advantage it offers is the fact that it does not bind its own this. In other words, the context inside arrow functions is lexically or statically defined.
What do we mean by that?
Unlike other functions, the value of this inside arrow functions is not dependent on how they are invoked or how they are defined.It depends only on its enclosing context.
Thus, regardless of whether the arrow function was called using function invocation or method invocation, it retains the value of this from its enclosing context.In other words, an arrow function’s this value is the same as it was immediately outside it.
If used outside any enclosing function, an arrow function inherits the global context, thereby setting the value of this to the global object.
In classic function expressions, the this keyword is bound to different values based on the context in which it is called.
There are a few subtle differences in behavior between ordinary function functions and arrow functions. Arrow functions do not have their own this value. The value of this inside an arrow function is always inherited from the enclosing scope.
Arrow Functions lexically bind their context so this actually refers to the originating context.
There are a few other differences: arrow functions don’t get their own arguments, super, or new.target keywords. Arrow functions are anonymous, which means that they are not named, so if your function needs to have a self-reference at any point (e.g. recursion, event handler that needs to unbind), it will not work.
More info https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/
A scope in JS is associated to a function. When you create an object using new, this is created in constructor.
const foo = new Foo();
foo.fn()
In above code, context is created in constructor and fn derives its context from foo.
How does this work?
A function has an internal property [[prototype]], which stores context. By default it is not set (or set to default global scope) and it derives/ overrides context via caller. So in foo.fn(), context refers to foo. But if you do var fn = foo.fn; fn(), here context is of global/default scope.
To avoid this, we use Arrow function. Arrow function does not have an internal context and uses the context it is defined in. So above code var fn = foo.fn; fn(); will work.
However, if you define Arrow function inside an object literal, it will still point to the parent scope it was defined in and will not fallback to object.
Sample:
function Foo1() {
this.fn = function () {
console.log(this.constructor.name, this);
}
}
var foo2 = {
fn: function() {
console.log(this.constructor.name, this);
}
}
function test() {
var foo3 = {
fn: function() {
console.log(this.constructor.name, this);
}
}
foo3.fn();
}
function test2() {
var foo3 = {
fn: () => {
console.log(this.constructor.name, this);
}
}
foo3.fn();
}
var foo1 = new Foo1();
foo1.fn();
foo2.fn();
test();
test2();

Lost context in object

I have this code:
/// global context
function Outer(){
/// Outer context
this.print = function(){
console.log("1: "+this)
inside(); /// "this" is bound to the global object. Why not bound to the Outer object?
function inside(){
console.log("2: "+this)
}
};
}
function print(){
console.log("3: "+this);
}
var obj = new Outer;
obj.print(); /// "this" is bound to the Outer object.
print(); /// "this" is bound to the global object.
Why inside the method call, this has a global object? Can anyone explain this?
That's because, its obeying following 2 JS rules
Rule 1. In Javascript, new function = new scope - that’s the rule.
Rule 2. When a function is called as a method of an object, this is set to the object the method is called on.
Explanation of the code:
For rule 2, this.print() is a feature of Outer object. So this will refer to the Outer object.
So the console.log 1 will print 1: [object Object]
For rule 1, the function inside() in Outer is not a feature of Outer object. So new scope will created and this assigned to window. And that's also same for the last function 'print()'
So console.log 2 will print 2: [object Window]
And console.log 3 will print 3: [object Window] as well
Hope Helps,
Run the code: https://es6console.com/j9bxeati/
Reference: https://toddmotto.com/everything-you-wanted-to-know-about-javascript-scope/#function-scope
As the reference states,
In most cases, the value of this is determined by how a function is called. It can't be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind method to set the value of a function's this regardless of how it's called, and ES2015 introduced arrow functions which do provide their own this binding (it remains the this value of the enclosing lexical context).
<...>
Inside a function, the value of this depends on how the function is called.
<...>
Since the following code is not in strict mode, and because the value of this is not set by the call, this will default to the global object
<...>
So, in strict mode, if this was not defined by the execution context, it remains undefined.
The posted code is not executed in strict mode, so this equals to global variable (window) inside the function when it's called like print().
If this is not the desirable behaviour, and print is expected to be called separately from the object it originally was defined on (e.g. when being passed as a callback), the function can be bound to its lexical this with arrow in ES6:
function Outer(){
this.print = () => { ... };
}
In ES5 bind or self = this recipe can be used:
function Outer(){
this.print = (function(){ ... }).bind(this);
}
function Outer(){
var self = this;
this.print = function(){
self;
...
};
}
If the function isn't expected to be called with another context, it can be called with another context in-place:
print.call(this);
Or:
print.bind(this)();
If it is not obvious for you, that probably means you confuse scope and context of the function.
Scope is what vars function has access to during invocation. Context (this) is determined by how function is invoked.
Now look on how you invoke your function 'inside' and answer the question. Does it vividly owned by any object? That is why you have global
The value of this is determined by how a function is called.
Your "inside" function was called inside "print" function, which has an object reference, but that object did not have "inside" function as a property or that object did not invoke "inside" function.
"this" refers to the object which called it, not the scope in which it is called.
Hence, the global object
the value of this is depends on how you are making a call to the intended function and generally leading parent object plays important role in it.
what does it mean by leading parent object?:
sampleObj.getDetails(); // here 'sampleObj' is the leading parent object for 'getDetails()' function
lets try to clear the things using some examples of making call to the function using below sample code snippet.
function globalFunction(){
console.log('global this: ', this);
}
var simpleObj = {
name : 'john'
};
var complexObj = {
outer: function(){
console.log('outer this: ', this);
}
}
globalFunction(); // will log global object as no leading parent object is available
complexObj.outer(); // will log 'complexObj' object as leading parent object is 'complexObj'
complexObj.outer = complexObj.outer.bind(simpleObj);
complexObj.outer(); // will log 'simpleObj' object as we have set preference as 'simpleObj' for this **
complexObj.outer.call(); // will log global object as we arent setting any preference for 'this' ***
complexObj.outer.call(simpleObj); // will log simpleObj object as we have set preference as simpleObj for 'this' ***
complexObj.outer.apply(); // will log global object as we arent setting any preference for 'this' ****
complexObj.outer.apply(simpleObj); // will log simpleObj object as we have set preference as simpleObj for 'this' ****
hopefully it will help you!
** what is bind: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
*** what is call: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
**** what is apply: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
You can understand it if you read about arrow functions new in ES6.
Until arrow functions, every new function defined its own this value
(a new object in the case of a constructor, undefined in strict mode
function calls, the base object if the function is called as an
"object method", etc.).
Which means that every function defines it's own this and in case of a simple function it will always be a global object and not the context of a function it is defined in. Just for comparison a function which doesn't define it's own this(an arrow function):
/// global context
function Outer(){
/// Outer context
this.print = function(){
console.log("1: "+this)
let inside = () => {
/// "this" is Outer object here
console.log("2: "+this)
}
inside();
};
}

Strange value for the "this" object

Regarding this code:
var name = "Jaguar";
var car = {
name:"Ferrari",
getName:function(){
return this.name;
}
};
alert((car.getName = car.getName)());
The output is: Jaguar.
Why does this object correspond to Window and not the object contained in the car variable?
It seems that the fact to reassign the object's function to itself leads to lose the assignment of this to the object when the function is called...
I'm trying to guess: Does it exist a kind of mechanism (using variable or other) that keep an eye on the non-reassignement of an object's function so that if that situation happens, this mechanism would prevent the assignement of the this keyword as usual (as being equals to the object)?
The reason is fairly subtle: this in JavaScript is determined entirely by how a function is called. To have this set to car during the call to getName, you have to call getName immediately upon retrieving it from the car object, like this:
car.getName() // or
car["getName"]()
(Or via Function#call or Function#apply, which let you specify the value for this explicitly.)
What you're doing in your example is effectively this:
// Set f to the result of the assignment expression,
// which is a reference to the getName function
var f = (car.getName = car.getName);
// Call it (separately)
f();
...which is different. Functions called in that way get this set to the global object (window, in browsers). (Except in strict mode; in strict mode this would be undefined.)
More (from my anemic blog):
Mythical methods
You must remember this
Does it exist a kind of mechanism (using variable or other) that keep an eye on the non-reassignement of an object's function so that if that situation happens, this mechanism would prevent the assignement of the this keyword as usual (as being equals to the object)?
I'm not entirely sure I follow that question, but if you want to have a function that always has a preset this value, then yes, there are a couple of ways to do that.
One is to use the new ES5 function bind:
var name = "Jaguar";
var car = {
name: "Ferrari"
};
car.getName = function(){
  return this.name;
}.bind(car);
alert((car.getName = car.getName)()); // "Ferrari"
bind returns a function that always has this set to the argument you give it.
The other way is to use a closure. And in fact, you can create a bind-like function in ES3 very easily:
function pseudoBind(func, thisArg) {
return function() {
return func.apply(thisArg, arguments);
};
}
That doesn't do everything bind does, but it does the this part. Then you'd have:
var name = "Jaguar";
var car = {
name: "Ferrari"
};
car.getName = pseudoBind(function(){
  return this.name;
}, car);
alert((car.getName = car.getName)()); // "Ferrari"
More on closures (again from the blog):
Closures are not complicated
In a future spec, we'll be getting a declarative way of creating functions that have a preset this value (so-called "arrow functions" because the syntax for them involves uses => rather than the function keyword).
Aaah, this resolution...Lets take a gander.
var toy = {
log : function () { console.log(this); }
};
toy.log() //logs the toy object
So far, it seems like this resolution is static: Wherever the method was defined in, that's its this value.
But! What if we do this:
var sneakyBastard = toy.log;
sneakyBastard(); //logs Window
this is bound to the object it's called with. In the case of toy.log, you called log in the context of the toy object. But, sneakyBastard has no set context, so it's as if you've called window.sneakyBastard.
Now let's take a goose (goose? gander? no...) at your expression:
(car.getName = car.getName)()
...and what does an assignment return? The assigned value, in this case, a function, car.getName. We can break this expression into two:
var returnedValue = (car.getName = car.getName);
returnedValue();
...and from here it's obvious.
Instead of calling getName from the context of an object, you're calling it from the context of the return result of the grouping operator (which in this case there's no context).
In JavaScript, when there's no clear context defined, a default is used. The default is...
the global object when in strict mode
undefined when not in strict mode
You have put your function call parenthesis (()) so they call the result of the expression (car.getName = car.getName) (which is the value (a function) assigned to car.getName)

Javascript: why "this" inside the private function refers to the global scope?

Consider the following code:
function A() {}
A.prototype.go = function() {
console.log(this); //A { go=function()}
var f = function() {
console.log(this); //Window
};
f();
}
var a = new A();
a.go();
Why does 'this' inside function 'f' refers to the global scope? Why it is not the scope of function 'A' ?
JavaScript has a different concept of what the special name this refers to
than most other programming languages do. There are exactly five different
ways in which the value of this can be bound in the language.
The Global Scope
this;
When using this in global scope, it will simply refer to the global object.
Calling a Function
foo();
Here, this will again refer to the global object.
ES5 Note: In strict mode, the global case no longer exists.
this will instead have the value of undefined in that case.
Calling a Method
test.foo();
In this example, this will refer to test.
Calling a Constructor
new foo();
A function call that is preceded by the new keyword acts as
a constructor. Inside the function, this will refer
to a newly created Object.
Explicit Setting of this
function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // array will expand to the below
foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3
When using the call or apply methods of Function.prototype, the value of
this inside the called function gets explicitly set to the first argument
of the corresponding function call.
As a result, in the above example the method case does not apply, and this
inside of foo will be set to bar.
Note: this cannot be used to refer to the object inside of an Object
literal. So var obj = {me: this} will not result in me referring to
obj, since this only gets bound by one of the five listed cases.
Common Pitfalls
While most of these cases make sense, the first one is to be considered another
mis-design of the language because it never has any practical use.
Foo.method = function() {
function test() {
// this is set to the global object
}
test();
}
A common misconception is that this inside of test refers to Foo; while in
fact, it does not.
In order to gain access to Foo from within test, it is necessary to create a
local variable inside of method which refers to Foo.
Foo.method = function() {
var that = this;
function test() {
// Use that instead of this here
}
test();
}
that is just a normal variable name, but it is commonly used for the reference to an
outer this. In combination with closures, it can also
be used to pass this values around.
Assigning Methods
Another thing that does not work in JavaScript is function aliasing, which is
assigning a method to a variable.
var test = someObject.methodTest;
test();
Due to the first case, test now acts like a plain function call; therefore,
this inside it will no longer refer to someObject.
While the late binding of this might seem like a bad idea at first, in
fact, it is what makes prototypal inheritance work.
function Foo() {}
Foo.prototype.method = function() {};
function Bar() {}
Bar.prototype = Foo.prototype;
new Bar().method();
When method gets called on a instance of Bar, this will now refer to that
very instance.
Disclaimer: Shamelessy stolen from my own resources at http://bonsaiden.github.com/JavaScript-Garden/#function.this
The reason why is you are invoking f as a function and not a method. When invoked as a function this is set to window during the execution of the target
// Method invocation. Invoking a member (go) of an object (a). Hence
// inside "go" this === a
a.go();
// Function invocation. Invoking a function directly and not as a member
// of an object. Hence inside "f" this === window
f();
// Function invocation.
var example = a.go;
example();
The scope of all functions is window.
To circumvent that, you can do this:
function A() {}
A.prototype.go = function() {
var self = this;
console.log(self); //A { go=function()}
var f = function() {
console.log(self); //A { go=function()}
};
f();
}
Because function f() is not called without any object reference. Try,
f.apply(this);

Categories

Resources