Chain custom javascript functions - javascript

After searching for quite some time, I still haven't found what I'm looking for.
There's a fair amount of examples that either require creating a new instance, or only have functions that don't return anything (which means the problem can be solved with returning this).
I hope the following example illustrates my point well:
// Say I have these functions
function aNumber(){
var max = 100, min = 0;
return (Math.floor(Math.random() * (max - min + 1)) + min);
}
function divideBy(_number, _divider){
return (_number / _divider);
}
function multiplyBy(_number, _multi){
return (_number * _multi);
}
function add(_number, _add){
return (_number + _add);
}
function subtract(_number, _sub){
return (_number - _sub);
}
// #########################################################
// I can do this with them
var test = aNumber();
test = divideBy(aNumber, 2);
test = add(aNumber, 5);
test = multiplyBy(aNumber, 3);
test = subtract(aNumber, 10);
// I would like to do this however:
var test = aNumber().divideBy(2).add(5).multiplyBy(3).subtract(10);
What would be the most efficient way to make the last line work?
Am I misinformed that this is possible without creating a new instance of something?

Yes, this requires changing the Prototype of an Object. Objects are instances. So you need to create an object to do this kind of thing.
function MyNum(value) {
this._val = value; // Having _variable is for denoting it is a private variable.
}
Initialize objects using:
var myNum = new MyNum(5);
And now using this, define these:
MyNum.prototype.divideBy = function () {}
MyNum.prototype.multiplyBy = function () {}
Don't forget to use return this; inside these functions.

Try like below for creating without instance and prototype keyword.
One more method is been added here you can set number or random number by default. if the number not specified.
var Calculator = {
setNumber: function(givenNumber) {
var max = 100,
min = 0;
this.number = (givenNumber) ? givenNumber : (Math.floor(Math.random() * (max - min + 1)) + min);
return this;
},
divideBy: function(_divider) {
this.number = (this.number / _divider);
return this;
},
multiplyBy: function(_multi) {
this.number = (this.number * _multi);
return this;
},
add: function(_add) {
this.number = (this.number + _add);
return this;
},
subtract: function(_sub) {
this.number = (this.number - _sub);
return this;
},
result: function () {
return this.number;
}
}
document.write('<pre>');
document.writeln(Calculator.setNumber(2).divideBy(2).add(5).multiplyBy(3).subtract(10).result());
document.writeln(Calculator.setNumber(4).divideBy(2).add(5).multiplyBy(3).subtract(10).number);
document.writeln(Calculator.setNumber().divideBy(2).add(5).multiplyBy(3).subtract(10).result());
document.write('</pre>');

Yes, you do need to create an instance of something. This can be a simple object literal, function constructor, etc...
The idea is that all of your methods are stored on some object, right? The only way to access those methods is to access them through that object. With this in mind, each function must RETURN the object that holds all of these methods.
A quick example
var myMethods = {
one: function() {
console.log('one');
// You can return 'this' or reference the object by name
return this;
// or
// return myMethods;
},
two: function() {
console.log('two');
return this;
}
};
myMethods.one().two().one().two();
//=> 'one', 'two', 'one', 'two'
Watch out when you reference the method directly, like so
var someMethod = myMethods.one;
someMethod() //=> undefined
This is because 'this' is now referencing the global object, which is another story for another day. Just watch out if you reference a method in this way.

Although it is generally not recommended to add functions to the prototype of JavaScript primitives, you can do what you are looking for by doing so.
function aNumber(){
var max = 100, min = 0;
return (Math.floor(Math.random() * (max - min + 1)) + min);
}
function divideBy(_number, _divider){
return (_number / _divider);
}
function multiplyBy(_number, _multi){
return (_number * _multi);
}
function add(_number, _add){
return (_number + _add);
}
function subtract(_number, _sub){
return (_number - _sub);
}
Number.prototype.divideBy = function(_divider){
return divideBy(this, _divider);
};
Number.prototype.multiplyBy = function(_multi){
return multiplyBy(this, _multi);
};
Number.prototype.add = function(_add){
return add(this, _add);
};
Number.prototype.subtract = function(_sub){
return subtract(this, _sub);
};
var test = aNumber().divideBy(2).add(5).multiplyBy(3).subtract(10);

Just like Praveen and Venkatraman said, I found the following posts about chaining, but there all have to declare a new instanse before accessing any methods for changing
method-chaining-in-javascript and beautiful-javascript-easily-create-chainable-cascading-methods-for-expressiveness
or you can use this implementation https://jsfiddle.net/ayinloya/zkys5dk6/
function aNumber() {
var max = 100;
var min = 0;
this._number = (Math.floor(Math.random() * (max - min + 1)) + min);
console.log("a init", this._number)
}
aNumber.prototype.divideBy = function(_divider) {
this._number = (this._number / _divider)
return this;
}
aNumber.prototype.multiplyBy = function(_multi) {
this._number = (this._number * _multi);
return this;
}
aNumber.prototype.add = function(_add) {
this._number = (this._number + _add);
return this;
}
aNumber.prototype.subtract = function(_sub) {
this._number = (this._number - _sub);
return this;
}
aNumber.prototype.ans = function() {
return this._number;
}
var a = new aNumber()
alert(a.add(2).subtract(1).ans())

If you don't want to pull in a library and want to have functions that are reusable (and not bind to a specific class, e.g. a Calculator). What you can do is to wrap the input into an array and then pass it through a series of map functions. In the end just take the first element and you will have your result.
function aNumber(){
var max = 100, min = 0;
return (Math.floor(Math.random() * (max - min + 1)) + min);
}
function divideBy(_number, _divider){
return (_number / _divider);
}
function multiplyBy(_number, _multi){
return (_number * _multi);
}
function add(_number, _add){
return (_number + _add);
}
function subtract(_number, _sub){
return (_number - _sub);
}
// #########################################################
var result = [aNumber()]
.map(item => divideBy(item, 2))
.map(item => add(item, 5))
.map(item => multiplyBy(item, 3))
.map(item => subtract(item, 10))
[0];
console.log(result);
This probably is not the most efficient way but usually speed is "good enough".

Related

The function `this` doesn't work in module of nodejs

I create a module with following
module.exports = {
GetRandomNum:(Min,Max)=>{
var Range = Max - Min;
var Rand = Math.random();
return(Min + Math.round(Rand * Range));
},
mathCalculationtion:()=>{
var firstPlace = this.GetRandomNum(1, 9);
return firstPlace;
}
}
I run this above code and get an error at the line var firstPlace = this.GetRandomNum(1, 9);
at Object. mathCalculationtion (/home/sfud/projectland/lib/comlib.js)
Please help me, thank you.
You are using arrow functions. The this variable does exist within regular objects, but arrow functions pull their this from whatever this is when they're declared (unless you bind them, which would be an odd thing to do).
Change your functions to functions and it should work fine.
module.exports = {
GetRandomNum(Min,Max) {
var Range = Max - Min;
var Rand = Math.random();
return(Min + Math.round(Rand * Range));
},
mathCalculationtion() {
var firstPlace = this.GetRandomNum(1, 9);
return firstPlace;
}
}
Note: To use it this way, you will need to import the module and call the function with the . syntax.
// This will work
const myModule = require('./my-module');
console.log(myModule.mathCalculationtion());
// This will not work
const { mathCalculationtion } = require('./my-module');
console.log(mathCalculationtion());
This is because this within the function is whatever the x in x.myFunc() is. If you just call myFunc() directly, it has no idea which object to apply it to. If you want to get around this, either define your functions in your module separately and reference them by name in the module, then export each function, or you can use .bind().
Change this.GetRandomNum(1, 9) to module.exports.GetRandomNum(1, 9) or
declare your functions outside of the module.exports block:
var getRandomNum = (Min,Max) => {
var Range = Max - Min;
var Rand = Math.random();
return(Min + Math.round(Rand * Range));
}
var mathCalculationtion = () => {
var firstPlace = getRandomNum(1, 9);
return firstPlace;
}
then:
module.exports = {
getRandomNum,
mathCalculationtion
}
Use module.exports instead of this:
module.exports = {
GetRandomNum(Min,Max) {
var Range = Max - Min;
var Rand = Math.random();
return(Min + Math.round(Rand * Range));
},
mathCalculationtion() {
var firstPlace = module.exports.GetRandomNum(1, 9);
return firstPlace;
}
}
It works for me just fine in NodeJs v12.16.1.

How to use other computed properties inside computed

I'm trying this:
props: ["gameState"],
computed: {
cards() {
return this.gameState.playerCards
},
rows() {
let cards = this.cards();
let max = 6;
if (cards.length <= max)
return [cards]
var mid = Math.ceil(cards.length / 2);
let return_value = [cards.slice(0, mid), cards.slice(mid)]
return return_value
}
}
but it tells me that this.cards is not a function. I was looking at Is it possible to use the computed properties to compute another properties in Vue? which said this should be the way to use other computed properties.
This is what I was explaining in comments.
computed: {
cards() {
return this.gameState.playerCards
},
rows() {
let cards = this.cards;
// if cards is ever undefined (maybe its populated asynchronously),
// cards.length will blow up. So, check here and return a sane
// value when it's undefined
if (!cards) return []
let max = 6;
if (cards.length <= max)
return [cards]
var mid = Math.ceil(cards.length / 2);
let return_value = [cards.slice(0, mid), cards.slice(mid)]
return return_value
}
}

Do I really need to use protoypes for this in javascript? (Practical example)

Can this be written without complexing things with prototypes?
Why? The current code does what I want, but it bothers me how trixy it is to follow and how error prone it is, also seems to be performance wasting since things are duplicated.
Aim? The more I spend using prototype and this I get the sense the code would be simpler and more to the point if this was not the case.
Especially if the this-functions in SystemBlueprint can be rewritten to take an instance as argument instead. And if object Function Log() and Out could just be plain objects somehow? How can Log or Out be extracted outside of SystemBuilder?
Full code in Jsbin
https://jsbin.com/pigosijaxo/edit?js,console (Updated)
// Local for each System object
var SystemData = {
name: '?',
id: 1,
actions: [],
destinations: []
}
// Variables shared among all Systems
const SystemShare = {
global: 1
}
// this-Functions shared among all Systems
function SystemBlueprint() {}
SystemBlueprint.prototype = {
run() {
var length = this.actions.length
for (var i = 0; i < length; i++) {
var result = this.actions[i](arguments, this)
if (result && this.destinations.length > 0) {
for (var n = 0; n < this.destinations.length; n++) {
this.destinations[n].call(null, result)
}
}
}
},
does(algorithm) {
this.actions.push(algorithm)
return this
},
random(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
}
function SystemBuilder(name) {
// copy shared methods
var system = Object.create(SystemBlueprint.prototype)
Object.assign(system, JSON.parse(JSON.stringify(SystemData))) //deep copy
system.name = name
system.id = SystemShare.global++
function Log() {}
Log.prototype.local = () => console.log('fields: ' + JSON.stringify(Object.keys(system))),
system.log = new Log()
function Out(){}
Out.prototype.into = (destination) => {
system.destinations.push(destination)
return system
}
system.out = new Out()
system.trigger = {}
function OnEvent(trigger){
if(trigger === undefined) return
trigger.call(null, system.run.bind(system))
return system
}
system.trigger.on = new OnEvent()
return system
}
var system = new SystemBuilder()
system.my = 'Testing'
system.log.local()
system.does( () => 'printing output...')
system.out.into(console.log)
system.run()
Partial Answer, implementation from comment suggestion by #Bellian, a bit on the way for sure, thanks!
Where? Inside function SystemBuilder(...):
Instead of
function Log() {}
Log.prototype.local = () => console.log('fields: ' + JSON.stringify(Object.keys(system))),
system.log = new Log()
Do this
function _local(system){
console.log('fields: ' + JSON.stringify(Object.keys(system)))
}
system.log = {local: _local.bind(this, system)}

Javascript Float32 array throws Cannot read property '0' of null even though array is well defined

Here you can see the debug window: http://i.imgur.com/ZnfeKT1.png
As you can see, the array is NOT null and has in fact 2 elements. Why the hell am I getting that error ?
Edit: This code was written in C# and converted to JS via DuoCode:
WebGL.Vector2 = $d.declare("WebGL.Vector2", null, 62, $asm, function($t, $p) {
$t.cctor = function() {
$t.GLVector2 = vec2;
};
$t.ctor = function Vector2() {
this.vec = null;
};
$t.ctor.prototype = $p;
$p.get_X = function Vector2_get_X() {
return this.vec[0]; //this is line 777
};
$p.set_X = function Vector2_set_X(value) {
this.vec[0] = value;
return value;
};
$p.get_Y = function Vector2_get_Y() {
return this.vec[1];
};
$p.set_Y = function Vector2_set_Y(value) {
this.vec[1] = value;
return value;
};
$p.get_Magnitude = function Vector2_get_Magnitude() {
return Math.sqrt(this.get_X() * this.get_X() + this.get_Y() * this.get_Y());
};
$p.get_Normalized = function Vector2_get_Normalized() {
var m = this.get_Magnitude();
return WebGL.Vector2.op_Division(this, m);
};
$t.ctor$1 = function Vector2() {
this.vec = $d.array(System.Single, 2);
this.set_X(0);
this.set_Y(0);
};
$t.ctor$1.prototype = $p;
$t.ctor$2 = function Vector2(x, y) {
this.vec = $d.array(System.Single, 2);
this.set_X(x);
this.set_Y(y);
};
$t.ctor$2.prototype = $p;
$p.Rotated = function Vector2_Rotated(angle) {
var rad = Math.PI * angle / 180;
var cs = Math.cos(rad);
var sn = Math.sin(rad);
return new WebGL.Vector2.ctor$2(this.get_X() * cs - this.get_Y() * sn, this.get_X() * sn + this.get_Y() * cs);
};
$p.Transformed = function Vector2_Transformed(matrix) {
var ret = new WebGL.Vector2.ctor$1();
$t().GLVector2.transformMat3(ret.vec, this.vec, matrix.mat);
return ret;
};
$t.op_Multiply = function Vector2_op_Multiply(v, f) {
return new WebGL.Vector2.ctor$2(v.get_X() * f, v.get_Y() * f);
};
$t.op_Division = function Vector2_op_Division(v, f) {
return new WebGL.Vector2.ctor$2(v.get_X() / f, v.get_Y() / f);
};
$t.op_Addition = function Vector2_op_Addition(v1, v2) {
return new WebGL.Vector2.ctor$2(v1.get_X() + v2.get_X(), v1.get_Y() + v2.get_Y());
};
$t.op_Subtraction = function Vector2_op_Subtraction(v1, v2) {
return new WebGL.Vector2.ctor$2(v1.get_X() - v2.get_X(), v1.get_Y() - v2.get_Y());
};
$t.Dot = function Vector2_Dot(v1, v2) {
return v1.get_X() * v2.get_X() + v1.get_Y() * v2.get_Y();
};
$p.ToString = function Vector2_ToString() {
return String.Format("[{0}, {1}]", $d.array(System.Object, [this.get_X(), this.get_Y()]));
};
});
You're right, this is a bad behavior, but it happens because of an experimental feature in C# 6 (parameterless constructors). Usually C# forbids declaring default constructors for structs, that's why there must be an automatic default ctor that initializes the struct (and sets null to reference-type fields like the array "vec").
C# 6 added the option for primary constructors - but Microsoft already realized that it's too complicated and I believe they plan to abandon this feature for now.
DuoCode uses Roslyn for compilation and that's the reason for this behavior. Next releases of Roslyn and DuoCode probably will forbid this.
I would recommend that you make your Vector2 struct as an immutable struct with two fields (x, y) - that would work the best.
Disclaimer: I work with the DuoCode developers
Edit: Oops, it's called parameterless constructors
Okay the problem was the following: For some reason, DuoCode generates a default constructor for structs which initializes value types with null. My custom default constructor is ONLY called when I explicitly call Vector2 v = new Vector2(). This behavior is pretty unexpected and quite annoying to be honest. I hope this will be fixed in later releases.

How to sort an Array of Points by their distance to a reference Point, in Javascript?

I have a working code, here:
function simpleDist(pointA, pointB) {
var x = pointA.x - pointB.x,
y = pointA.y - pointB.y;
return Math.sqrt(x*x + y*y);
}
function sortByDist(pointRef, pointArray) {
var distancePairs = [],
output = [];
for(var p in pointArray) {
var pointComp = pointArray[p];
distancePairs.push([simpleDist(pointRef,pointComp), p]);
}
distancePairs.sort(function(a,b) {
return a[0]-b[0];
});
for(var p in distancePairs) {
var pair = distancePairs[p];
output.push(pointArray[pair[1]]);
}
return output;
}
And this works, for what I'm doing. However, I'm wondering if there is a more simplified way to do it using Array.sort(). I have looked at several explanations of Array.sort() and it seems like it would need to accept 3 functions to perform what I need without the workaround here. I feel like I'm just being dense, though. Can you see any way to make this function faster, or more simplified?
I think that you are pretty much on the right track.
If you are trying to optimize for lines of code, then you can use Array.prototype.map to reduce some the boiler-plate array code.
Using a similar sorting implementation
function simpleDist(pointA, pointB) {
var x = pointA.x - pointB.x,
y = pointA.y - pointB.y;
return Math.sqrt(x*x + y*y);
}
var sortByDist = (function() {
var comparator = function(a,b) { return a.value - b.value; };
return function (pointRef, pointArray) {
var reorder = function(e) { return pointArray[e.index]; };
var distanceFromArray = function(b,i) {
return { index: i, value: simpleDist(pointRef, b) };
};
return pointArray.map(distanceFromArray).sort(comparator).map(reorder);
};
}());
The only "direct" way I can think to simplify the implementation would be to use memoization to optimize calls to simpleDist.
function simpleDist(pointA, pointB) {
var x = pointA.x - pointB.x,
y = pointA.y - pointB.y;
return Math.sqrt(x*x + y*y);
}
// fn(point) memoizer
var memoizer = (function(fn) {
var cache = {};
return function(pointB) {
var key = pointB.x + "|" + pointB.y; // simple key hashing
return cache[key] || (cache[key] = fn(pointB));
};
}());
function sortByDist (pointRef, pointArray) {
// partially apply pointRef to simpleDist and memoize
var distanceFrom = memoizer(function(pointB) { return simpleDist(pointRef, pointB); });
// sort
return pointArray.sort(function(a,b) {
return distanceFrom(a) - distanceFrom(b);
});
}
Given that simpleDist is a pure function -- the same inputs always produce the same outputs -- the memoizer here prevents you from incurring the cost of repeated distance calculations. With a little more setup overhead, then the sort becomes a simple comparator.
UPDATE
Here is how my code can be modified to use memoize decorator.
The good thing about it that memoization doesn't depend much on implementation of compared things.
I am not sure though how fast is JSON.stringify() (but fast enough it seems, and hashing function can be changed after all).
function memoized(fn) {
var lookupTable = {};
var keymaker = function (args) {
console.log(JSON.stringify(args));
return JSON.stringify(args)
};
return function () {
var key = keymaker.call(this, arguments);
return lookupTable[key] || (
lookupTable[key] = fn.apply(this, arguments))
}
}
function simpleDist(pointA, pointB) {
var x = pointA.x - pointB.x,
y = pointA.y - pointB.y;
return Math.sqrt(x * x + y * y);
}
function distanceFrom(pointC) {
return function (pointA, pointB) {
var distA = simpleDist(pointA, pointC);
var distB = simpleDist(pointB, pointC);
if (distA < distB) return -1;
if (distA > distB) return 1;
return 0;
}
}
var distanceFromC = memoized(distanceFrom({x:0, y:0}));
[{x:10, y:10}, {x:1, y:2},{x:3, y:1}, {x:3, y:2}].sort(distanceFromC);
OLD
function simpleDist(pointA, pointB) {
var x = pointA.x - pointB.x,
y = pointA.y - pointB.y;
return Math.sqrt(x*x + y*y);
}
//returns comparator function for specified point
function distanceFrom(pointC) {
return function(pointA, pointB) {
var distA = simpleDist(pointA, pointC);
var distB = simpleDist(pointB, pointC);
if (distA < distB)
return -1;
if (distA > distB)
return 1;
return 0;
}
}
//now we can create separator functions for each ponts we like
var distanceFromC = distanceFrom({x:0, y:0});
var distanceFromD = distanceFrom({x:10, y:10});
//just keep in mind that built-in sort modifies initial list
console.log([{x:10, y:10}, {x:1, y:2}].sort(distanceFromC)); //{1,2}, {10,10}
console.log([{x:10, y:10}, {x:1, y:2}].sort(distanceFromD)); //{10,10}, {1,2}
Here I used the fact that closures and the fact that they can access outer function parameters even after outer function returns.
You can read more about it, for example, in David Herman's Effective Javascript chapter 2.11 or here

Categories

Resources