Hoisted method in javascript - javascript

I would like to learn the proper way to hoisted method in object.
My goal is the put the object definition at the end of the code, and the object usage at the beginning. Let's say:
doing stuff with o
let o = {
bar: 1,
foo: function() {
console.log(this.bar);
},
}
Of course, if I'm writing :
o.foo();
let o = {
bar: 1,
foo: function() {
console.log(this.bar);
},
}
o is undefined because the object is declared after the usage.
I thought about this trick :
o = returnO();
o.foo();
function returnO() {
return o = {
bar: 1,
foo: function() {
console.log(this.bar);
},
}
}
which works but I would like to know if there's not a better way to avoid the statement
o = returnO();
Thanks.

I don't know what's the purpose of what you want to accomplish, maybe you're practicing.
The problem is the post declaration of the variable, the engine at this point of the interpretation of your code o.foo();, the variable o was declared but not yet initialized.
You can use a function declaration (Hoisted function) as follow, and use it as a constructor which is similar to what you want to accomplish:
new A().foo();
function A() {
this.bar = 1;
this.foo = function() {
console.log(this.bar);
};
}

Related

Get reference of a function located in the same object

I cannot figure out why the following does not work:
var foo = { f1: () => 5, f2: this.f1() }
I get this error:
TypeError: this.f1 is not a function
It seems that this refers to the global scope instead of foo. Everything works fine with the following:
var foo = { f1: () => 5, f2() { return this.f1 } }
Is there a way to refer to f1 without wrapping it in a new function?
The scope where you're executing the assignment is global scope, so this is not foo. One might think that this would then fix it:
var foo = { f1: () => 5, f2: foo.f1() }
but it doesn't - because at the time when the literal is constructing the object, the assignment hasn't happened, and foo is still undefined.
You need to take timing into account, and write one of the following:
var foo = { f1: () => 5 }
foo.f2 = foo.f1
or
var f = () => 5
var foo = { f1: f, f2: f }
Of course, if you want to simply resolve to f1 at runtime, and don't want to explicitly invoke a function with parentheses, you can still sneak in a function as a getter:
var foo = { f1: () => 5, get f2() { return foo.f1 } }
foo.f2
# => [Function: f1]
This answer is probably helpful:
How does the "this" keyword in Javascript act within an object literal?
This answer also has useful comments on the difference between arrow and regular functions, particularly how this is affected in each:
Arrow functions vs Fat arrow functions
var testOne = {
a: 'hello',
b: () => console.log(this.a)
}
var testTwo = {}
testTwo.a = 'hello'
testTwo.b = function() {console.log(this.a)}
console.log(testOne.a)
testOne.b()
console.log(testTwo.a)
testTwo.b()

Why can't I use a defined function inside another defined function,when creating an js object?

The code goes like this
var ob = {
a: function() {
b()
},
b: function() {
console.log("hi")
}
};
As you can see, you can't do
ob.a() //returns error
Can someone explain the reason in depth?
Becuase b does not exist in the current scope (which is the global one in this case).
This works, however:
var ob = {
a: function () {
this.b()
},
b: function () {
console.log('hi')
}
};
because this refers to the ob object.
There is no function b defined anywhere, it's a property of object ob, so you can refer it as this.b from inside a:
var ob = {
a: function () {
this.b();
},
b: function () {
console.log("hi");
}
};
ob.a();
You could also access b as ob.b().
The b is a property of the object called ob. That being said, if you use
ob.b
instead of b you will solve your problem.
var ob = {
a:function(){
ob.b()
},
b:function(){
console.log("hi")
}
};
Another way to do achieve this is to use the this operator.
var ob = {
a:function(){
this.b()
},
b:function(){
console.log("hi")
}
};
The this holds a reference to the object you define. Hence using it you can access is properties. It is a better way that the first way, because if you decide later to alter the name of ob to obj, you will not have change it in two places.

How can I share an object between my modules?

So I have a helper module H, which I require from my main script M:
M.js:
var o = {foo: 'bar'};
require('H.js').doFunc();
H.js:
module.exports = {doFunc: function(){ /* how can I set X to o.foo in M's scope? */ return X; }};
Thus one can expose things in this direction. What can I do to share things back the other way?
You can't quite do it the way you intend because node's architecture creates separate, individual global objects per module. However, you can get something similar using the mechanics of how this works in javascript.
In plain js, given:
function doFunc () {
return this.foo;
}
var o = {foo:'bar'};
You can do:
o.dofunc = doFunc;
o.doFunc(); // returns 'bar'
Alternatively:
doFunc.call(o); // also returns 'bar'
So, applying this technique to modules:
In H.js:
module.exports.doFunc = function () {return this.foo}
In M.js:
var o = {
foo: 'bar',
dofunc : require('H.js').doFunc
};
o.dofunc();
M.js
var o = {foo: 'bar'};
require('H.js')(o);
H.js
module.exports = function (o) {
console.log(o);
}
M:
o = {foo: 'bar'};
require('./H.js')(); // 'bar'
H:
module.exports = o.foo;
By not declaring the variable, it gets stored on the global object which is shared.

Javascript Prototype Oriented Programming doubts

I want to do the following in Javascript
function A(){
this.B = function() { ... };
this.C = function() { <<I need to call B() here>> } ;
};
I have read the following way of method overloading, but I want to know whether professional programmers would do it this way. I.e. if you would only do this as an exercise or experiment or would actually do this in production code.
function foo(a, b, opts) {
};
foo(1, 2, {"method":"add"});
foo(3, 4, {"test":"equals", "bar":"tree"});
Just call B() from inside C();
function A(){
B = function() {
// Do something here
}
C = function() { B(); }
};
Or, if you just want to create an alias
function A(){
B = function() {
// Do something here
}
C = B
};
The clean way would be :
var A = function() { };
A.prototype.B = function() { };
A.prototype.C = function() { this.B(); };
The prototype is just a static set of properties that is cloned inside every new instance you create.
The difference between what you're doing and this is that in your case, methods are created and added when you are in the "constructor" of the object, while with this method they already are properties of the object before you enter its "constructor", and are only parsed once (when you add them to the prototype) instead of being parsed everytime you create a new instance, which is faster.
I think, correct me if i'm wrong.
var A = function() {
// this scope is what i mean by "constructor".
};

JavaScript scope: referencing parent object member from child member's closure

Newbie to JavaScript here.
How do I reference member foo from within member foobar, given that foobar's in a closure?
var priv = {
foo: "bar",
foobar: (function() {
return this.foo === "bar";
})()
};
The code above fails. In it, this.foo is undefined. If I change this.foo to priv.foo, it's still undefined. How do I reference priv.foo from within the foobar closure?
It's impossible to read any properties of an object in its defination during its initialization since prev will be undefined at that time.
When you're trying to call a clojure inside it, it refers to undefined this or priv.
Probably you wanted to write:
foobar: (function() {
return this.foo === "bar";
})
without () in the end. And then you could call it as priv.foobar();
If you still need to call it, you could define foobar after foo:
var priv = {
foo: "bar"
};
priv.foobar = (function() {
return priv.foo === "bar";
})()
The problem is that you aren't defining a closure - I don't think that there is any way to access foo from your function as priv is not yet initialised.
What exactly are you trying to do? The following is equivalent to what I understand your sample is trying to do, but my guess is that I'm not understanding the problem:
// Set elsewhere
var foo = "bar";
var priv = {
foo: foo ,
foobar: foo == "bar"
};

Categories

Resources