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();
}
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();
I am writing one tool in node js. I wanted to define some POJO in node js. I don't have much experience in Node js. I came from JAVA background where classes are used for defining entities. One way, in which I have define entities now are:-
function Person(name) {
this.name = name;
this.values = [];
this.characteristics = {};
}
But this is defined in one JS file. And to make it available in other JS files, I have to export this function. Is this the best way to define entities or are there any other way in which I can define something of class kind of format?
That is just fine for creating objects. If you start to use a DB like mongo, you might be better off creating objects with mongoose but that's personal preference as well. As for your example -
1) Export Person
module.exports = Person;
2) Import Person from another file
const Person = require('../path/to/Person');
3) Create Person with the new keyword to call the constructor (very important)
const mitch = new Person('Mitch');
You should read up on javascript's prototype. Every object has a reference to Object.prototype. Then you can create objects with Object.create(obj) to create objects and assign the new object's prototype as the reference being passed in to Object.create(obj)
Here's an example from MDN
// Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}
// superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); // call super constructor.
}
// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.log('Is rect an instance of Rectangle?',
rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'
JavaScript allows functions to be treated as objects--if you first define a variable as a function, you can subsequently add properties to that function. How do you do the reverse, and add a function to an "object"?
This works:
var foo = function() { return 1; };
foo.baz = "qqqq";
At this point, foo() calls the function, and foo.baz has the value "qqqq".
However, if you do the property assignment part first, how do you subsequently assign a function to the variable?
var bar = { baz: "qqqq" };
What can I do now to arrange for bar.baz to have the value "qqqq" and bar() to call the function?
It's easy to be confused here, but you can't (easily or clearly or as far as I know) do what you want. Hopefully this will help clear things up.
First, every object in Javascript inherits from the Object object.
//these do the same thing
var foo = new Object();
var bar = {};
Second, functions ARE objects in Javascript. Specifically, they're a Function object. The Function object inherits from the Object object. Checkout the Function constructor
var foo = new Function();
var bar = function(){};
function baz(){};
Once you declare a variable to be an "Object" you can't (easily or clearly or as far as I know) convert it to a Function object. You'd need to declare a new Object of type Function (with the function constructor, assigning a variable an anonymous function etc.), and copy over any properties of methods from your old object.
Finally, anticipating a possible question, even once something is declared as a function, you can't (as far as I know) change the functionBody/source.
There doesn't appear to be a standard way to do it, but this works.
WHY however, is the question.
function functionize( obj , func )
{
out = func;
for( i in obj ){ out[i] = obj[i]; } ;
return out;
}
x = { a: 1, b: 2 };
x = functionize( x , function(){ return "hello world"; } );
x() ==> "hello world"
There is simply no other way to acheive this,
doing
x={}
x()
WILL return a "type error". because "x" is an "object" and you can't change it. its about as sensible as trying to do
x = 1
x[50] = 5
print x[50]
it won't work. 1 is an integer. integers don't have array methods. you can't make it.
Object types are functions and an object itself is a function instantiation.
alert([Array, Boolean, Date, Function, Number, Object, RegExp, String].join('\n\n'))
displays (in FireFox):
function Array() {
[native code]
}
function Boolean() {
[native code]
}
function Date() {
[native code]
}
function Function() {
[native code]
}
function Number() {
[native code]
}
function Object() {
[native code]
}
function RegExp() {
[native code]
}
function String() {
[native code]
}
In particular, note a Function object, function Function() { [native code] }, is defined as a recurrence relation (a recursive definition using itself).
Also, note that the answer 124402#124402 is incomplete regarding 1[50]=5. This DOES assign a property to a Number object and IS valid Javascript. Observe,
alert([
[].prop="a",
true.sna="fu",
(new Date()).tar="fu",
function(){}.fu="bar",
123[40]=4,
{}.forty=2,
/(?:)/.forty2="life",
"abc".def="ghi"
].join("\t"))
displays
a fu fu bar 4 2 life ghi
interpreting and executing correctly according to Javascript's "Rules of Engagement".
Of course there is always a wrinkle and manifest by =. An object is often "short-circuited" to its value instead of a full fledged entity when assigned to a variable. This is an issue with Boolean objects and boolean values.
Explicit object identification resolves this issue.
x=new Number(1); x[50]=5; alert(x[50]);
"Overloading" is quite a legitimate Javascript exercise and explicitly endorsed with mechanisms like prototyping though code obfuscation can be a hazard.
Final note:
alert( 123 . x = "not" );
alert( (123). x = "Yes!" ); /* ()'s elevate to full object status */
Use a temporary variable:
var xxx = function()...
then copy all the properties from the original object:
for (var p in bar) { xxx[p] = bar[p]; }
finally reassign the new function with the old properties to the original variable:
bar = xxx;
var A = function(foo) {
var B = function() {
return A.prototype.constructor.apply(B, arguments);
};
B.prototype = A.prototype;
return B;
};
NB: Post written in the style of how I solved the issue. I'm not 100% sure it is usable in the OP's case.
I found this post while looking for a way to convert objects created on the server and delivered to the client by JSON / ajax.
Which effectively left me in the same situation as the OP, an object that I wanted to be convert into a function so as to be able to create instances of it on the client.
In the end I came up with this, which is working (so far at least):
var parentObj = {}
parentObj.createFunc = function (model)
{
// allow it to be instantiated
parentObj[model._type] = function()
{
return (function (model)
{
// jQuery used to clone the model
var that = $.extend(true, null, model);
return that;
})(model);
}
}
Which can then be used like:
var data = { _type: "Example", foo: "bar" };
parentObject.createFunc(data);
var instance = new parentObject.Example();
In my case I actually wanted to have functions associated with the resulting object instances, and also be able to pass in parameters at the time of instantiating it.
So my code was:
var parentObj = {};
// base model contains client only stuff
parentObj.baseModel =
{
parameter1: null,
parameter2: null,
parameterN: null,
func1: function ()
{
return this.parameter2;
},
func2: function (inParams)
{
return this._variable2;
}
}
// create a troop type
parentObj.createModel = function (data)
{
var model = $.extend({}, parentObj.baseModel, data);
// allow it to be instantiated
parentObj[model._type] = function(parameter1, parameter2, parameterN)
{
return (function (model)
{
var that = $.extend(true, null, model);
that.parameter1 = parameter1;
that.parameter2 = parameter2;
that.parameterN = parameterN;
return that;
})(model);
}
}
And was called thus:
// models received from an AJAX call
var models = [
{ _type="Foo", _variable1: "FooVal", _variable2: "FooVal" },
{ _type="Bar", _variable1: "BarVal", _variable2: "BarVal" },
{ _type="FooBar", _variable1: "FooBarVal", _variable2: "FooBarVal" }
];
for(var i = 0; i < models.length; i++)
{
parentObj.createFunc(models[i]);
}
And then they can be used:
var test1 = new parentObj.Foo(1,2,3);
var test2 = new parentObj.Bar("a","b","c");
var test3 = new parentObj.FooBar("x","y","z");
// test1.parameter1 == 1
// test1._variable1 == "FooVal"
// test1.func1() == 2
// test2.parameter2 == "a"
// test2._variable2 == "BarVal"
// test2.func2() == "BarVal"
// etc
Here's easiest way to do this that I've found:
let bar = { baz: "qqqq" };
bar = Object.assign(() => console.log("do something"), bar)
This uses Object.assign to concisely make copies of all the the properties of bar onto a function.
Alternatively you could use some proxy magic.
JavaScript allows functions to be
treated as objects--you can add a
property to a function. How do you do
the reverse, and add a function to an
object?
You appear to be a bit confused. Functions, in JavaScript, are objects. And variables are variable. You wouldn't expect this to work:
var three = 3;
three = 4;
assert(three === 3);
...so why would you expect that assigning a function to your variable would somehow preserve its previous value? Perhaps some annotations will clarify things for you:
// assigns an anonymous function to the variable "foo"
var foo = function() { return 1; };
// assigns a string to the property "baz" on the object
// referenced by "foo" (which, in this case, happens to be a function)
foo.baz = "qqqq";
var bar = {
baz: "qqqq",
runFunc: function() {
return 1;
}
};
alert(bar.baz); // should produce qqqq
alert(bar.runFunc()); // should produce 1
I think you're looking for this.
can also be written like this:
function Bar() {
this.baz = "qqqq";
this.runFunc = function() {
return 1;
}
}
nBar = new Bar();
alert(nBar.baz); // should produce qqqq
alert(nBar.runFunc()); // should produce 1
I'm trying to pass a Class reference and instantiate it in a function. This doesn't work:
function foo(myClassRef:Class):Void {
var myVar = new myClassRef();
}
foo(MyClass);
It gives Unexpected (.
Is this possible in Haxe 3?
Class has a Type Parameter, so if you're going to accept a class as an argument, you need to specify a type parameter.
Accept any class:
function foo(myClassRef:Class<Dynamic>):Void {
var myVar = Type.createInstance( myClassRef, [constructorArg1, constructorArg2....] );
trace( Type.typeof(myVar) );
}
Accept only "sys.db.Object" class or sub classes:
function foo(myClassRef:Class<sys.db.Object>):Void {
var myVar = Type.createInstance( myClassRef, [] );
trace( Type.typeof(myVar) );
}
Haxe 3 also allows generic functions:
#:generic function foo<T:Dynamic>(t:Class<T>) {
var myVar = new T();
trace( Type.typeof(myVar) );
}
Here you declare the function to be generic, which means that for each different type parameter, a different version of the function will be compiled. You accept Class, where T is the type parameter - in this case, dynamic, so it will work with any class. Finally, using generic functions let's you write new T(), which may seem a more natural syntax, and there may be performance benefits on some platforms.
It is possible in Haxe3 and Haxe2
function foo<T>(myClassRef:T):Void {
var myVar = new T();
}
Note: Haxe3 class (where foo is implemented) must be #:generic if you want new T() to work.
Haxe2 is another story:
function foo<T>(myClassRef:Class<T>):Void {
var myVar = Type.createEmptyInstance(Type.getClass(myClassRef));
}