Create new this on method call - node.js

This may be a stupid question, but is it possible to create a new this on a method call of a class?
E.g:
const foo = new Foo();
console.log(foo.a(1).b(2));
// for example, outputs 3 (1+2)
// the a method will create a new namespace and attach 1 to it, and b will use that new namespace
console.log(foo.b(2));
// this will result in an error, as there is no new namespace from the a method anymore, so b cannot add to anything?
Maybe this is too hard to understand, sorry.
class Foo {
a(number) {
this.a = number;
return this;
}
b(number) {
return this.a + number;
}
}
This would be the code where it uses the same this variable - this doesn't fit what I wanted but is what I currently have.
// pseudo
class Foo {
a(number) {
const uniqueVariable = number
return uniqueVariable
// it'll somehow pass the number from this method to the next method
}
// where it can be used with the second method's input
b(uniqueVariable, number) {
return uniqueVariable + number
}
}
foo.a(1).b(2) = 3
This example would obviously cause an error because the return value of a() a number, not something to use a method on again.
Please let me know if I need to explain further -- I'm having some struggle explaining it properly.

If the intention is that foo.a(1).b(2) changes foo, or if you don't mind changing foo, the other answers here work.
But if you only want foo.a(1).b(2) to return 3 without modifying foo, then you need to return a new Foo.
Now, if you really hell bent on having console.log() print 3 rather than something like Foo { value: 3 }, you can also customize inspect() (given that the question is tagged with node.js).
All together:
const util = require('util');
class Foo {
constructor(value) {
this.value = value || 0;
}
add(value) {
return new Foo(this.value + value);
}
a(value) {
return this.add(value);
}
b(value) {
return this.add(value);
}
[util.inspect.custom]() {
return this.value;
}
}
const foo = new Foo();
console.log(foo);
console.log(foo.a(2).b(1));
console.log(foo);
Output:
0
3
0

On my solution, I decided to create two variables to hold the values of each method. (https://jsbin.com/wozuyefebu/edit?js,console)
The a() method will return a number if the isSingle parameter is set to true. If not, it will return the this object, allowing you to chain the b() method. This is might be a hack but I believe it solves your problem.
I write about Javascript and web development on my blog :) https://changani.me/blog
class Foo {
constructor() {
this.aValue = 0;
this.bValue = 0;
}
/**
* #param {Number} value
* #param {Boolean} isSingle
* #returns {Object/Number}
*/
a(value = 0, isSingle = false) {
this.aValue = value;
return isSingle ? this.aValue : this;
}
/**
* #param {Number} value
* #returns {Number}
*/
b(value = 0) {
this.bValue = this.aValue + value;
return this.bValue;
}
}
const x = new Foo();
console.log("Should return 3: ", x.a(2).b(1));
console.log("Should return an 2: ", x.a(2, true));
console.log("Should return an instance of the object: ", x.a(2));
console.log("Should return 1: ", x.b(1));
console.log("Should return 0: ", x.a().b());
(https://jsbin.com/wozuyefebu/edit?js,console)

If you want to be able to invoke methods on return value of methods, then, you should return this from those methods. However, you will need an additional method, say value() to actuall get the result of sum.
A possible way is show below.
class Foo {
_a = 0;
_b = 0;
a(number) {
this._a = number;
return this;
}
b(number) {
this._b = number;
return this;
}
value() {
return this._a + this._b;
}
}
const foo = new Foo();
console.log(foo.a(1).b(2).value());
console.log(foo.b(5).value());

Related

Reimplement function in terms of existing function

Let's suppose I have this simple code:
const a = {
number: 2,
method() {
return this.number
}
}
console.log(a.method()) // prints 2
Now I'd like to reimplement method in terms of method itself. Ideally:
a.method = function() {
return 40 + this.method() // should print 42, get a RangeError: Maximum call stack size exceeded
}
Is there a way to achieve this?
You could try something like this:
const a = {
number: 2,
method() {
return this.number
}
}
// 1. Store old method
var oldMethod = a.method.bind(a)
// 2. Reference old method in new declaration
a.method = function() {
return 40 + oldMethod()
}
console.log(a.method())
See MDN for more info on .bind.

Could haxe macro be used to detect when object is dirty (any property has been changed)

Let say we have an object:
#:checkDirty
class Test {
var a:Int;
var b(default, default):String;
var c(get, set):Array<Int>;
public function new() {
...
}
public function get_c() {
...
}
public function set_c(n) {
...
}
}
Could we write a macro checkDirty so that any change to field/properties would set property dirty to true. Macro would generate dirty field as Bool and clearDirty function to set it to false.
var test = new Test();
trace(test.dirty); // false
test.a = 12;
trace(test.dirty); // true
test.clearDirty();
trace(test.dirty); //false
test.b = "test"
trace(test.dirty); //true
test.clearDirty();
test.c = [1,2,3];
trace(test.dirty); //true
Just to note - whenever you consider proxying access to an object, in my experience, there are always hidden costs / added complexity. :)
That said, you have a few approaches:
First, if you want it to be pure Haxe, then either a macro or an abstract can get the job done. Either way, you're effectively transforming every property access into a function call that sets the value and also sets dirty.
For example, an abstract using the #:resolve getter and setter can be found in the NME source code, replicated here for convenience:
#:forward(decode,toString)
abstract URLVariables(URLVariablesBase)
{
public function new(?inEncoded:String)
{
this = new URLVariablesBase(inEncoded);
}
#:resolve
public function set(name:String, value:String) : String
{
return this.set(name,value);
}
#:resolve
public function get(name:String):String
{
return this.get(name);
}
}
This may be an older syntax, I'm not sure... also look at the operator overloading examples on the Haxe manual:
#:op(a.b) public function fieldRead(name:String)
return this.indexOf(name);
#:op(a.b) public function fieldWrite(name:String, value:String)
return this.split(name).join(value);
Second, I'd just point out that if the underlying language / runtime supports some kind of Proxy object (e.g. JavaScript Proxy), and macro / abstract isn't working as expected, then you could build your functionality on top of that.
I wrote a post (archive) about doing this kind of thing (except for emitting events) before - you can use a #:build macro to modify class members, be it appending an extra assignment into setter or replacing the field with a property.
So a modified version might look like so:
class Macro {
public static macro function build():Array<Field> {
var fields = Context.getBuildFields();
for (field in fields.copy()) { // (copy fields so that we don't go over freshly added ones)
switch (field.kind) {
case FVar(fieldType, fieldExpr), FProp("default", "default", fieldType, fieldExpr):
var fieldName = field.name;
if (fieldName == "dirty") continue;
var setterName = "set_" + fieldName;
var tmp_class = macro class {
public var $fieldName(default, set):$fieldType = $fieldExpr;
public function $setterName(v:$fieldType):$fieldType {
$i{fieldName} = v;
this.dirty = true;
return v;
}
};
for (mcf in tmp_class.fields) fields.push(mcf);
fields.remove(field);
case FProp(_, "set", t, e):
var setter = Lambda.find(fields, (f) -> f.name == "set_" + field.name);
if (setter == null) continue;
switch (setter.kind) {
case FFun(f):
f.expr = macro { dirty = true; ${f.expr}; };
default:
}
default:
}
}
if (Lambda.find(fields, (f) -> f.name == "dirty") == null) fields.push((macro class {
public var dirty:Bool = false;
}).fields[0]);
return fields;
}
}
which, if used as
#:build(Macro.build())
#:keep class Some {
public function new() {}
public var one:Int;
public var two(default, set):String;
function set_two(v:String):String {
two = v;
return v;
}
}
Would emit the following JS:
var Some = function() {
this.dirty = false;
};
Some.prototype = {
set_two: function(v) {
this.dirty = true;
this.two = v;
return v;
}
,set_one: function(v) {
this.one = v;
this.dirty = true;
return v;
}
};

mockito spy doesn't work on android studio

I'm trying to mock some object and manipulate the return value of the object's method. After applying spy or mock, seems manipulating the return value doesn't work. The final result 'res' is not '10' as I expected but '1'. After instantiating class B and call the method getAAA(), it just calls the real method of A.aaa() and returns '1'.
class A {
public int aaa() { return 1; }
}
class B {
A classA;
B(A classA) { this.classA = classA; }
public int getAAA() { return classA.aaa(); }
}
A spyA = mock(A.class);
when(spyA.aaa()).thenReturn(10);
A AA = new A();
int res = new B(AA).getAAA();
Logxx.d("RESULT: " + res);
RESULT: 1
You are not using your mock/ spy instead you are creating new object with new.
Also, you are mocking the object with mock(...) but you are calling you object as spy(spyA). This isn't wrong since it is just a variable name. But not readable.
A mockA = mock(A.class);
when(spyA.aaa()).thenReturn(10);
A AA = new A();
int res = new B(mockA).getAAA();
Logxx.d("RESULT: " + res);

Define a literal Javascript object so a property referenced directly calls a function and not its sub-ordinates [duplicate]

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

Do we have to return value at setter?

In haxe documentation of properties, there is the example:
class C {
public var x(get,set) : Int;
function get_x(){ return 123; }
function set_x(value){
doSomethingWith(value);
return 123;
}
}
But why do we have to return a value in setter of x above? is there a good reason?
The reason is, in Haxe, the assignment expression does return a value, eg.
var a;
trace(a = 3.14);//3.14
It is natural since we can chain assignments together:
var test = a = 3.14; //test will be 3.14
For example there is a weird class,
class Weird {
public function new():Void {}
public var x(get, set):Int;
function get_x() return x;
function set_x(v:Int):Int {
x = v;
return 123;
}
}
var weird = new Weird();
trace(weird.x = 456); //123
trace(weird.x); //456
var test = weird.x = 456; //test will be 123
But of course, usually we simply return the input of the setter, because it is more logical:
function set_x(v:Int):Int {
return x = v;
}
Sometimes it's just nice to have a setter function return the previous value, so you can code like this:
oldval=set(newval);
do_something();
set(oldval);
to temporarily set a new value, then restore the old one after you've finished.

Resources