Interdependent includes in node.js result in a empty object - javascript

I have two files that declare a class, both of them with static functions:
foo.js:
const bar = require('./bar');
console.log('bar in foo: ');
console.log(bar);
class foo {
static _(test) {
return 'foo_' + test + bar._(test);
}
static bar() {
return 'bar';
}
}
module.exports = foo;
bar.js:
const foo = require('./foo');
console.log('foo in bar:');
console.log(foo);
class bar {
static _(test) {
return foo.bar(test);
}
}
module.exports = bar;
In VS Code, code completion work in both files to get the other file's static method.
But when I try to execute it:
const foo = require('./foo');
foo._('test');
I can see that the recursive require don't work as I thought it would:
foo in bar:
{}
bar in foo:
[Function: bar]
bar.js:8
return foo.bar(test);
^
TypeError: foo.bar is not a function
I know class in JS are syntaxic sugar around functions, but I am still surprised that the interpreter lose static members.
Can anybody explain the working of require in that case? And why it result in a empty object?

Related

Generically apply context to method aliases

I an encountering a problem which I can't solve. I don't know whether it is a lack knowledge, or the fact that it is not even possible in Javascript, but I hope to get to know it.
I am trying to execute a list of function aliases in an object. When executing these functions, I would like to use them as if they were executed right from the instance itself, So I can use other methods and instance variables within that called method. To make my explaination a bit more clear, here is an example:
class Bar {
constructor() {
this.name = "Bar";
}
someMethod() {
console.log(this.name) // should log Bar
}
}
class Foo {
constructor() {
this.name = "Foo";
}
someOtherMethod() {
console.log(this.name) // should log Foo
}
}
const bar = new Bar();
const foo = new Foo();
const methodList = {
foo: bar.someMethod,
baz: foo.someOtherMethod,
}
for(let prop in methodList) {
methodList[prop](); // logs 2x undefined
}
for(let prop in methodList) {
methodList[prop].apply(foo); //logs 2x Foo
}
As can be seen in the example above, this.name is a variable in the instance of the class. When executing the second loop, a context is applied and logs correctly, as expected. I would like to see that context being applied automatically, since the function alias object is executed in a different file, not knowing about foo or bar and just receiving the list.
Is there any way to achieve this?
You could wrap your foo and bar methods in a function of their own. Within these methods you could then call the object's method someMethod()/someOtherMethod() on the object like so:
const methodList = {
foo: (...args) => bar.someMethod(...args),
baz: (...args) => foo.someOtherMethod(...args),
}
At the moment your first loop doesn't work because your this doesn't refer to the actual context of the object as that isn't what is used to invoke the method. It instead refers to your methodList
See example bellow:
class Bar {
constructor() {
this.name = "Bar";
}
someMethod() {
console.log(this.name) // should log Bar
}
}
class Foo {
constructor() {
this.name = "Foo";
}
someOtherMethod() {
console.log(this.name) // should log Foo
}
}
const bar = new Bar();
const foo = new Foo();
const methodList = {
foo: (...args) => bar.someMethod(...args),
baz: (...args) => foo.someOtherMethod(...args),
}
for(let prop in methodList) {
methodList[prop](); // correct logs
}
This happens because the contextual this when invoking methodList[prop]
is methodList, hence this in someMethod and someOtherMethod is actually:
{
foo: bar.someMethod,
baz: foo.someOtherMethod,
}
To solve the issue, you can wrap the methods in an anonymous function returning the invoked method, as shown below:
class Bar {
constructor() {
this.name = "Bar";
}
someMethod(a,b,c) {
console.log(a,b,c,this.name) // should log Bar
}
}
class Foo {
constructor() {
this.name = "Foo";
}
someOtherMethod(a,b,c) {
console.log(a,b,c,this.name) // should log Foo
}
}
const bar = new Bar();
const foo = new Foo();
const methodList = {
foo: (...args) => bar.someMethod(...args), // <-- anonymous function that, once invoked, returns `bar.someMethod()`, hence the contextual `this` of someMethod will be `bar`.
baz: function() { // <-- same as above, just written without the lambda notation.
return foo.someOtherMethod(...arguments);
}//^
}// | <-- that evaluation is actually calling the above code block.
// |-------------------------------------|
for(let prop in methodList) {// |
methodList[prop](1,4,'hello'); // <------|
}

When is an object completely defined?

I'm learning javascript and want to define 2 classes inside an object. The second class is derived from the first class.
It looks like:
let foo = {
bar: (function () {
let bar_msg = '';
class bar {
constructor(msg) {
bar_msg = msg;
}
}
return bar;
}()),
baz: (function () {
let baz_msg = '';
class baz extends foo.bar {
constructor(msg) {
super();
baz_msg = msg;
}
}
return baz;
}())
};
Error message:
Uncaught ReferenceError: foo is not defined
Then, I've tried to split the classes to multiple parts:
let foo = {};
foo.bar = (function () {
let bar_msg = '';
class bar {
constructor(msg) {
bar_msg = msg;
}
}
return bar;
}());
foo.baz = (function () {
let baz_msg = '';
class baz extends foo.bar {
constructor(msg) {
super();
baz_msg = msg;
}
msg() {
return baz_msg;
}
}
return baz;
}());
let b = new foo.baz('hi!');
console.log(b.msg());
It works.
So, my question is: Why do I get the difference? I cannot show some google search results because I have no idea about the keywords.
An object is 'completely' defined when you declared it and assign it a value like so:
var foo = 'bar';
You may declare a variable but not assign it to any value:
var foo;
and when you try to access it, it will give you undefined. You may also assign a value to an undeclared variable:
foo = 'bar';
And the javascript will automatically create a global variable foo. If you try to access a variable that has never been declared or implicitly declared (e.g foo = 'bar'). It will throw an error;
console.log(iDoNotExist); // will throw an error!
In your first code, the class baz, could not locate foo in its own scope, so it will go to the global scope. But since it's also not available in the global scope and it has neither been declared explicitly nor implicitly, it will throw an error.
In the second code, you have explicitly declared foo and assign it to an object and added a property bar right after it. Any code written after foo is declared would be able to access it, including when you assign the property bar to foo, in which a class called baz tries to extend foo.bar. If the piece of code that tries to extend foo or foo.bar is written after the definition of foo. It will throw an error. See snippet below for example:
class baz extends foo {
constructor(msg) {
super();
baz_msg = msg;
}
msg() {
return baz_msg;
}
}
let foo = {};
let b = new foo.baz('hi!');
In summary, you get the difference because the accessibility of foo. In the first variable you try to access it before it is both neither explicitly nor implicitly defined, resulting in an error. In the second variable, you've declared and assigned it to a value and try to access it after, which is perfectly legal.

How do I export an ES6 class and construct an instance of it in another module?

Using Node.js version 7.7.2, I'd like to define and export an ES6 class from a module like this:
// Foo.js
class Foo {
construct() {
this.bar = 'bar';
}
}
module.exports = Foo;
And then import the class into another module and construct an instance of said class like this:
// Bar.js
require('./foo');
var foo = new Foo();
var fooBar = foo.bar;
However, this syntax does not work. Is what I am trying to do possible, and if so, what is the correct syntax to achieve this?
Thanks.
You have to use regular node module syntax for this.
You have a few mistakes in your sample code. First, the class should not be followed by (). Also, a class constructor should be constructor not construct. Look at the below foo.js for proper syntax.
foo.js
class Foo {
constructor () {
this.foo = 'bar';
}
}
module.exports = Foo;
bar.js
const Foo = require('./foo');
const foo = new Foo();
console.log(foo.foo); // => bar
// Foo.js
export class Foo() {
construct() {
this.foo = 'bar';
}
}
notice keyword EXPORT

Why can't the functions in my CoffeeScript class 'see' other?

My foo.coffee looks like this:
class window.Foo
bar: () ->
baz()
baz: () ->
"baz"
In the Google Chrome Console, why then do I get the following?
f = new Foo
▶ Foo {}
f.baz
"baz"
f.bar
▶ Uncaught ReferenceError: baz is not defined(…)
You need to understand how the class abstraction works. Foo is a function with its own scope, so you might think you are defining inner functions that exist in the same scope. But you aren't. This is (more or less) the code that actually gets produced:
var Foo = function Foo() {};
Foo.prototype.bar = function() {
return baz();
};
Foo.prototype.baz = function() {
return "baz";
};
So bar only exists on Foo's prototype. Because of the way the new operator works in javascript, each instance of Foo gets a pointer to that function. You can reference these prototype functions with this which in coffeescript is abbreviated to #.
class Foo
bar: () ->
#baz()
baz: () ->
'baz'
You could alternatively (although it defeats the point of using classes) say:
class Foo
bar: () ->
Foo.prototype.baz()
baz: () ->
'baz'
you're missing the # sign - reference to this/self
class window.Foo
bar: () ->
#baz()
baz: () ->
"baz"

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