Do arrow functions not bind `this` inside ES6 classes? [duplicate] - node.js

This question already has answers here:
ES6 arrow function lexical this in V8
(2 answers)
Closed 7 years ago.
I'm surprised this doesn't work. (I'm running iojs 2.3.0 with the --harmony_arrow_functions flag.)
class Foo {
constructor() { this.foo = "foo"; }
sayHi() { return (() => this.foo)(); }
}
f = new Foo();
f.sayHi // Cannot read property 'foo' of undefined.
I would have expected the arrow function to pick up the right value for this. Am I missing something?

I don't know the problem, but my version works fine for me:
class Foo {
constructor() {
this.foo = "foo";
}
sayHi() {
return (() => console.log(this.foo))();
}
}
const f = new Foo();
f.sayHi();
BTW: I am using babel

Your IIFE is creating a new scope. this is then referring to the scope of the IIFE where this.foo is undefined.
The way you'd get around this is by binding your IIFE.
class Foo {
constructor() {
this.foo = 'foo';
}
sayHi() {
return (() => {
return this.foo;
}.bind(this))();
}
}
let f = new Foo();
console.log(f.sayHi()); //foo

Related

How can I declare variable for a module in TypeScript?

I have two files: index.ts and A.ts
A.ts:
export default class {
do() {
console.log(someVar);
}
}
index.ts:
import A from './A';
function printIt(param) {
let someVar = param;
let a = new A();
a.do();
}
printIt('wow'); // Console output: wow
printIt('123'); // Console output: 123
Is it real to declare someVar for A.ts from index.ts without wrapping A class?
I know that Node.JS wrappes all modules in (function (exports, require, module, __filename, __dirname, process, global) { }: How to change the Node.js module wrapper?
I tried to make a custom require function and pass my var like an argument. But I don't understand how can I make own require function in TypScript. Are there any ideas?
The scope of variables depends on where they are defined, not where they are called. this is on purpose, so you do not accidentally call on variables you did not know about being in the same scope as your function's invocation.
You must explicitly tell the code you want to pass this new variable into it, either just like Lux showed, or through passing it to the function like:
export default class {
do(someVar) {
console.log(someVar);
}
}
function printIt(param) {
let someVar = param;
let a = new A();
a.do(someVar);
}
what you're trying to do is akin to having everything be a global variable.
if you MUST do this (you shouldn't), there is one way you can.
export default class {
do() {
console.log(global.someVar);
}
}
function printIt(param) {
global.someVar = param;
let a = new A();
a.do();
}
There's many reasons why you do not want to do global variables, here are some
Edits after clarification:
So the "this" keyword inside of a module refers to the module's global scope, so I tried the following snippet:
// modA.js
const moduleContext = this
class ExportedClass {
printer() {
console.log(moduleContext.someVar)
}
}
module.exports = { ExportedClass }
//modB.js
let A = require("./modA")
A.someVar = "hello world"
let obj = new A.ExportedClass()
obj.printer()
and it seems the context was removed, the same thing with ES6 imports using mjs files, what did Work however is this:
//modA.js
function printer() {
console.log(this.someVar)
}
module.exports = { printer }
//modB.js
let A = require("./modA")
A.someVar = "hello world"
A.printer()
it seems moduleContext points to the old module context object, and the new imported module has a different context object.
This still seems like a bad idea though, you're better off structuring your code so that you export a constructing function, that takes whatever needs to be "global" for that scope, and sets it inside.
What are you trying to do? The seperation for module is on purpose, so the scope of everything remains.
Next, you have a typo: it should probably be let a = new A(); not let a = new A;.
But why dont you just pass the variable as an argument to the constructor of your A class?
export default class {
someVar: string;
constructor(someVar) {
this.someVar = someVar;
}
do() {
console.log(this.someVar);
}
}
now you can just do
function printIt(param) {
let someVar = param;
let a = new A(someVar);
a.do();
}

Does nodejs requires bind class method?

I am using node 12 in my project. Back to 2 years ago, I remember I need to bind method for class instance method like below:
class Logger {
constructor () {
this.printName = this.printName.bind(this);
}
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
But recently I found I don't need to call bind in the constructor. Does the latest node version support auto-bind already?
The behavior hasn't changed. The situation in which you need to .bind is when the instance's printName method would otherwise get called without a calling context. For example:
class Logger {
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();
or with, instead of fn:
setTimeout(l.printName)
or with:
button.addEventListener('click', l.printName)`
In all of these situations, an error will be thrown if you don't use .bind, because the method gets called without a calling context - but the calling context of the Logger instance is needed for this to refer to the instance, so that this.print refers to the print method of the instance.
This sort of thing has always been true in Javascript. Nothing's changed in the past few years, except that it's now a bit easier to bind - you can use new class field syntax instead of having a constructor:
class Logger {
printName = (name = 'there') => {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();

this is undefined in extended class

I have these 3 files:
bar.js
class Bar {
test(p) {
console.log(p);
}
}
module.exports = Bar;
baz.js
const Bar = require('./bar');
class Baz extends Bar {
test2(p) {
this.test(p);
}
}
module.exports = Baz;
foo.js
const Baz = require('./baz');
const { test2 } = new Baz();
test2('test');
When I passed 'test' to new Baz.test2(), I expected it to pass it to it's superclass (this.test(p)) where it should log 'test'. However, it threw the error:
this.test(p);
^
TypeError: Cannot read property 'test' of undefined
What am I doing wrong? Why is this undefined, I thought it should reference the class itself?
test2 is used apart from it's original context (Bar instance) and should be bound to proper this.
It's impossible to say from the name if it's expected to be a callback by design. In case it is, it can be bound in constructor:
class Bar {
constructor () {
this.test = this.test.bind(this);
}
...
}
Otherwise it can be bound in-place:
const test2 = new Baz().test2.bind(this);
test2('test');
Or just not be used separately from the context:
const baz = new Baz()
baz.test2('test');

Nested reference to `this` in ES6 classes [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
Take the following example;
class MyClass {
run() {
this.hello = 1;
co(function*() {
this.hello // this is now 'undefined'
})
}
}
new MyClass().run()
In ES5 I would normally assign this to another variable at the start of the function, such as var cls = this, but I would have hoped that ES6/ES7 would of solved this problem by now.
Is there a better way to do this?
You can use bind:
class MyClass {
run() {
this.hello = 1;
co(function*() {
this.hello // 1
}.bind(this));
}
}
new MyClass().run()

Groovy closures, def vs typed return value

In the Groovy console, version 2.2.1:
Why does this work?
class C {
def foo = { "foo" }
def bar = { foo() }
}
new C().bar()
but this fails?
class C {
String foo = { "foo" }
String bar = { foo() }
}
new C().bar()
The above was answered by tim_yates but I have something somewhat related that doesn't seem like it's worth creating a new question for (not sure of the etiquette). When I make them static it also fails when I call bar(). Why does the bar closure not capture foo?
class C {
static foo = { "foo" }
static bar = { foo() }
}
C.foo() //works
C.bar() //fails
Because neither { "foo" } or { foo() } are Strings?
They are Closure<String>
Try:
class C {
Closure<String> foo = { "foo" }
Closure<String> bar = { foo() }
}
new C().bar()

Resources