execution context and (( this object )) - javascript

// I don't understand why this is not working
y = 'window';
var x = {
y : 'x',
func : function(){
return function(){
return this.y
}
}
};
x.func()();
// when I execute x.func()() I understand why it should return y
// x.func() would return a function in the global context and then execute it ' should return 'window' '
y = 'window'
var x = {
y : 'x',
func : function(){
return function(){
return this.y
}()
}
};
x.func();
why would this code also return 'window' it is executed inside of the x object

The call x.func()() calls the function x.func using x as a context, then calls the value it returned using no context. Where the function was defined doesn’t matter; only how it was called does.
To avoid this, you can bind the function to a particular context before returning that:
var x = {
y: 'x',
func: function() {
return function() {
return this.y;
}.bind(this);
}
};
ES6 arrow functions also use a lexical this, equivalent to bind:
var x = {
y: 'x',
func: function() {
return () => this.y;
}
};

Related

Javascript accessing scope by using bind

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);

functions inside array to ignore the array's scope

I have a constructor and am trying to have an array of functions inside its prototype, but i need the functions to have the scope of the object created by the constructor, and not the array's scope.
I tried using .bind(this) or .bind(_p) but "this" is the node server's scope and _p is just the prototype without the variables.
function BoardModel() {
this.x = 3
this.y = 2
}
_p = BoardModel.prototype;
_p.skillFunctions = [
function(){
console.log(this.x); //undefined
},
function(){
console.log(this.y); //undefined
},
];
Why not use an own method for each property, instead of an array?
function BoardModel() {
this.x = 3
this.y = 2
}
_p = BoardModel.prototype;
_p.skillFunctionsX = function (){
console.log(this.x);
};
_p.skillFunctionsY = function (){
console.log(this.y);
};
var item = new BoardModel;
item.skillFunctionsX();
item.skillFunctionsY();
Arrow functions use this from the enclosing context so how about this (pun intended)?
function BoardModel() {
this.x = 3
this.y = 2
this.skillFunctions = [
() => { console.log(this.x) },
() => { console.log(this.y) },
];
}
let board = new BoardModel()
board.skillFunctions.forEach((skillFunction) => { skillFunction() })

Why am I getting undefined on this module pattern in javascript?

Why am I getting undefined on the x.test()? It's an anonymous function.
var Calculator = function () {
// private stuff
var x = 55;
return {
// public members
y: x,
test: function () {
console.log(x);
}
};
};
var x = new Calculator();
console.log(x.y);
console.log(x.test());
You're logging the return value of x.test which is implicitly undefined:
console.log(x.y); // Logs 55
var x = x.test(); // Logs 55 (because of the console.log call in x.test)
console.log(x); // Logs undefined (because that's what x.test returned)
Did you mean to return the "private" x from the test method?
// ...
return {
y: x,
test: function () {
return x;
}
}
Because you are printing (console.log) the return of a function that doesn't return anything.
Just return the x value in your test function:
var Calculator = function () {
// private stuff
var x = 55;
return {
// public members
y: x,
test: function () {
return x;
}
};
};

How do I reference an object property in an anonymous function within the same object?

var foo = {
x: 1,
y: (function () {
return ++this.x;
})()
};
console.log(foo.y); // undefined rather than 2
Let's say that I want to be able to reference foo.y without using foo.y(). Is that possible?
The above obviously doesn't work, and I'm assuming it is because closure references a different this.
If you want to access y as a property and not a function, and have it return the current value of foo.x, the only way I can think of is using getters/setters, which is part of the ES5 spec, and adopted in most of the modern browsers (but not really useable if you're supporting older browsers).
var foo = {
x: 1,
get y() {
return this.x;
}
};
You don't declare y as function, but as a result of a function call. It should be:
var foo = {
x: 1,
y: function () {
return this.x;
}
};
Or, if you want just to assign to y value of x:
var foo = {
x: 1,
y: this.x
};
UPDATE: It is NOT possible to make y synonym of x. When you declare y - it can be a value or a function. It cannot be a reference to another value.
Why not just return x directly if you don't want to use y() as a function? The only reason why you would return a function is you actually need to modify x's result.
var foo = {
x: 1,
y: (function () {
return this.x;
})()};
console.log(foo.x); // 1
var foo = new Object();
foo.x = 1;
foo.y = function() { return this.x; };
console.log(foo.y());
or if you're trying to invoke y while you define foo:
var foo = new Object();
foo.x = 1;
foo.y = x;
console.log(foo.y);
foo.y isn't a function. foo.y is defined as foo.x.

Javascript oop-like fail(?!?)

Consider this:
function f2(x) {
return x+1;
};
X = function(){
this.f1=function (x) {
return 2*f2(x);
}
return this;
};
then x = new X(); x.f1(1) works fine.
But when i want to do this:
X = function(){
this.f2 = function(x) {
return x+1;
};
this.f1=function (x) {
return 2*f2(x);
}
return this;
};
The same statement will complain that it can't find f2.
In, for example c#, you can say
class X {
int f2(int x){return x+1;}
int f1(int x){return 2*f2(x);}
}
and this will work
X x=new X();
x.f1(1)
Why?
You need to reference the f2 with the this keyword explicitly.
X = function(){
this.f2 = function(x) {
return x+1;
};
this.f1=function (x) {
return 2*this.f2(x);
}
return this;
};
because you forgot this.f2. Javascript don't see class variables without this
To reference f2 in your second code block, you'll need to use this.f2. this references the context in which the function is being executed. Since you call f1 in the following way:
x.f1();
... the context is set to the instance, x.
JavaScript does not make instance variables available to the scope in the same way as scope variables, i.e. those directly available:
X = function(){
var f2 = 123;
this.f2 = function(x) {
return x+1;
};
this.f1=function (x) {
console.log(f2); // => 123
console.log(this.f2); // => function(){}
return 2 * this.f2(x);
};
return this;
};
Javascript doesn't have the implicit this that you get in C#. You need to add the this in:
X = function(){
this.f2 = function(x) {
return x+1;
};
this.f1=function (x) {
return 2*this.f2(x);
};
return this;
};
X = function(){
this.f2 = function(x) {
return x+1;
};
this.f1=function (x) {
return 2*this.f2(x); // <-- Need this here since it is not implicit
}
return this;
};

Categories