I have 2 functions and one constructor defined like this :
let mx = function(arr) {
return new mx.fn.init(arr)
}
mx.fn = mx.prototype = {
constructor: mx,
}
init = mx.fn.init = function(arr) {
//do things and return an object containing data about arr
}
So this code works well and calling mx(array) returns the wanted object.
Now, how can I define functions to manipulate this object? I would like to define functions like, for example, mx(array).addRow(row) to change data in the object returned by mx(array) but can't manage to do it.
I tried to define it in mx.fn like this :
addRow: function(arr) { //do smth } but it doesn't work.
I also tried to do mx.prototype.addRow = function(row) { //do smth }.
Do you know if this is possible? It looks like jQuery's $('#id').css('color': 'red') a lot but I'm not sure if this works the same way.
I'm new to a lot of these concepts so I'm a bit lost in all those prototypes...
Thanks in advance for your help!
You need to set the prototype of the init function.
let mx = function(arr) {
return new mx.fn.init(arr)
}
let init = function(arr) {
//do things and return an object containing data about arr
}
mx.fn = init.prototype = {
addRow(row){
// do something
},
init: init
}
So I'm trying to make it so foo() returns anything from a string to object, then have foo().bar() return something completely different and even have foo().bar().test() return another thing completely different. For example, databases() would return something like a list of databases, then databases().users() would return an object of all the users and finally databases().users().ids() would return an array of IDs.
I think it's called function/method chaining but I haven't found anything related to what I need.
All I find is examples like var number = new math(10) number.add(5).subtract(3).value but I don't want it to chain it like that, I want it very linear (I don't know how to explain). I don't want to be able to use number.subtract(3).add(5).value or databases().ids().users() and I don't want to have to have .value at the end.
var math = function (n) {
this.value = n;
this.add = function (x) {
this.value += x;
return this;
};
this.subtract = function (x) {
this.value -= x;
return this;
};
};
var number = new math(10);
console.log(number.add(5).subtract(3).value);
The node js module, moment, works the way I'd like my project to work. moment() returns Moment<...>, moment().hours() returns the hour and moment().format("YYYY/MM/DD") returns 2020/10/22.
You can do something like this if you want number capacity and limited string capacity:
class Database extends String {
valueOf() { return 2 }
users() { return { ids: () => [] } }
};
const database = (val) => new Database(val || "")
Then you will be able to do this database() + 2 === 4, all string methods will be available and you will be able to do this database().users().ids()
I am using node.js.
I have a function that can be called this way;
add_row({location:'L1', row_name:'r1', value:'18.4'});
I have a string like this;
var str_param = "location:'L1', row_name:'r1', value:'18.4'";
I tried to do something like this to keep my code simple;
add_row(str_param);
It did not work. What is a good way to use str_param to call add_row?
You could convert the string to an object that the function accepts.
function toObj(str) {
const a = str.split(/,.?/g);
return a.reduce((p, c) => {
const kv = c.replace(/'/g, '').split(':');
p[kv[0]] = kv[1];
return p;
}, {});
}
toObj(str); // { location: "L1", row_name: "r1", value: "18.4" }
DEMO
I think this may be your issue:
{location:'L1', row_name:'r1', value:'18.4'} // Object
var str_param = "location:'L1', row_name:'r1', value:'18.4'"; // Not object
var str_param = "{location:'L1', row_name:'r1', value:'18.4'}"; // Object String
I do not use Node JS but just taking a shot in dark. If not you could just make function like:
function addRow(pLocation, pRowName, pValue) {
var row = {
location: pLocation,
row_name: pRowName,
value: pValue
}
// Logic ....
}
If that does not work try using Object string and look at function ParseJSON I believe it's called.
I'm just getting into functional programming and i'm having a hard time figuring out how to do this (if it's even worth the trouble). I've looked into currying and am not sure if this is the direction I need to go?? Or pipelines?
I would like to start with a value and then pipe it through different functions. Underscore has the 'chain' method which is similar. However I don't want to use prototypes to do this. I realize the solution might not match my target syntax.
Elm has the |> syntax (below) which is really nice to look at
// what i'd like to do (or similar) in JS *without using prototype*
num = ("(123) 456-7890")
.removeDashes()
.removeParens()
.removeSpaces()
// what elm does
"(123) 456-7890"
|> removeDashes
|> removeParens
|> rem
// functions I wrote so far
removeDashes = function(str) {
return str.replace(/-/g, '');
};
removeParens = function(str) {
return str.replace(/\(|\)/g, '');
};
removeSpaces = function(str) {
return str.replace(/\s/g, '');
};
// what i'm currently doing
num =
removeDashes(
removeParens(
removeSpaces(
"(123) 456-7890"")));
If you want to get you're feet wet with functional programming in JavaScript I'd advice you to use a library like Underscore, Lodash or Ramda. Which all have a compose/pipe functionality. Most of the times you'd want to combine it with some form of partial application which those libraries also provide.
Anyway it's a nice exercise to try to implement it yourself.
I would solve it like this...
/* Asumes es5 or higher */
function pipe (firstFn /* ...restFns */) {
var _ = null;
var _slice = Array.prototype.slice;
var restFns = _slice.call(arguments, 1) || [];
return function exec_fns() {
var args = _slice.call(arguments, 0, 1);
return restFns.reduce(function(acc, fn) {
return fn.call(_, acc);
}, firstFn.apply(_, args));
}
}
removeDashes = function(str) {
return str.replace(/-/g, '');
};
removeParens = function(str) {
return str.replace(/\(|\)/g, '');
};
removeSpaces = function(str) {
return str.replace(/\s/g, '');
};
console.log(pipe(
removeDashes,
removeParens,
removeSpaces
)("(123) 456-7890") == "1234567890")
Also Functional JavaScript by Fogus is a nice resource to dig deeper into this style of programming
There are different ways to tackle this problem, and you've offered references in underscore and Elm.
In Elm, curried functions are an important part of the equation. As every function receives a single argument, you can build chains with some of them partially applied, waiting for the argument you're weaving in with the pipeline. The same applies to Haskell, PureScript and languages of their ilk.
Reproducing that ipsis literis in JavaScript requires a little bit of sugar — you can use a sweet.js macro to get a source transformation that does it.
Without sugar, it can go many ways. Maybe one way to explore is using generators, passing the bits of the resolved chain down until you get a non-function value.
Like hindmost said, look into using prototypes. The string prototype allows you to add class-level functionality to all strings:
String.prototype.removeParens = function() {
this = this.replace(/\(|\)/g, '');
}
This lets you do things like this:
var myString = "(test)";
myString.removeParens();
And once you add the other functions to the String prototype you can simply chain the function calls like this:
myString.removeDashes().removeParens().removeSpaces();
etc.
You can create the pipe function in one line, with good readability:
const pipe = (...fns) => fns.reduce((v, f) => v.constructor === Function ? v() : f(v));
and it would be used in this way:
var numResult = pipe('(123) 456-7890', removeDashes, removeParens, removeSpaces);
var pipe = (...fns) => fns.reduce((v, f) => v.constructor === Function ? v() : f(v));
function removeDashes(str) {
return str.replace(/-/g, '');
}
function removeParens(str) {
return str.replace(/\(|\)/g, '');
}
function removeSpaces(str) {
return str.replace(/\s/g, '');
}
console.log(
'result:', pipe('(123) 456-7890', removeDashes, removeParens, removeSpaces)
);
Attention: this function needs a platform with support for the spread operator ....
Just in case, i've created a module for this with support for async functions (Promises) and it also works on older/legacy platforms that can't use the spread ...
https://github.com/DiegoZoracKy/pipe-functions
The easiest way is to really just add those to the prototype chain, but you can do that with an object. Here's an easy example:
function MyString( str ){
var value = str.toString();
return {
removeDashes: function() {
value = value.replace(/-/g, '');
return this;
},
removeParens: function() {
value = value.replace(/\(|\)/g, '');
return this;
},
removeSpaces: function() {
value = value.replace(/\s/g, '');
return this;
},
toString: function (){
return value;
},
valueOf: function (){
return value;
}
};
}
You can later on do this:
var clean = (new MyString('This \\(Is)\/ Dirty'))
.removeDashes()
.removeParens()
.removeSpaces();
This way, you will keep your prototype clean. To retrieve a non-object value, just run the toStrong() method, toValue() or do anything with the value (contatenating 1, divide it, anything!).
Here's a solution I found with lodash, it allows you to mixin your own functions and then use them against chain:
...
removeSpaces = function(str) {
return str.replace(/\s/g, '');
};
_.mixin({
removeSpaces: removeSpaces,
removeParens: removeParens,
removeDashes: removeDashes
});
num = _.chain("(123) 456-7890")
.removeSpaces()
.removeParens()
.removeDashes()
.value()
Not a very serious suggestions, but one that will work:
var update = pipe()(removeDashes >> removeParens >> removeSpaces);
update("(123) 456-7890"); //=> "1234567890"
This is based upon this implementation of pipe:
var pipe = function() {
var queue = [];
var valueOf = Function.prototype.valueOf;
Function.prototype.valueOf = function() {
queue.push(this);
return 1;
};
return function() {
Function.prototype.valueOf = valueOf;
return function(x) {
for (var i = 0, val = x, len = queue.length; i < len; i++) {
val = queue[i](val);
}
return val;
}
};
};
You can see more in slide 33 of my talk on functional composition in js.
As the others have said, adding the functions to the String prototype is a valid and short solution. However, if you don´t want to add them to String prototype or if you want to perform in the future more complex functions, another option is to make a wrapper to handle this:
function SpecialString(str){
this.str = str;
this.removeDashes = function() {
this.str=this.str.replace(/-/g, '');
return this;
};
this.removeParens = function() {
this.str=this.str.replace(/\(|\)/g, '');
return this;
};
this.removeSpaces = function() {
this.str=this.str.replace(/\s/g, '');
return this;
};
return this;
}
num = new SpecialString("(123) 456-7890").removeDashes().removeParens().removeSpaces();
console.log(num) // 1234567890
I am using https://stackoverflow.com/a/1833851 to clone a function so that I can override it. For example:
Function.prototype.clone = function() {
var that = this;
var temp = function temporary() { return that.apply(this, arguments); };
for(var key in this) {
if (this.hasOwnProperty(key)) {
temp[key] = this[key];
}
}
return temp;
};
window.capture_list = [];
window.handler_clone = window.YAHOO.handleData.clone();
window.YAHOO.handleData = function(oRequest, oResponse, oData){
window.capture_list.push( {'oRequest': oRequest, 'oResponse': oResponse, 'oData': oData} );
return window.handler_clone( oRequest, oResponse, oData );
};
This appears to achieve the task, but I get a "Maximum call stack size exceeded error" in practice.
It seems like the clone method I'm using is recursing into itself somehow... I think I'm misunderstanding something about this clone implementation due to my limited js experience.
Any thoughts on where this recursion is, or how to better implement the clone for overriding? I'm really just trying to intercept the arguments passed to handler(). Thanks!
the handleData function:
window.YAHOO.handleData = function(oRequest, oResponse, oData) {
if (oData == null) {
oData = {}
}
oData.totalRecords = oResponse.meta.totalRecords;
return oData
};
Stepping through this:
Clone copies this then applies any arguments to the original function, then iterates the keys in function (I am assuming to get the prototype properties?), then returning that back out.
It seems like you are trying to create a decorator?
In any case, I am not sure why you haven't opted to use bind it creates a new function with the context that is passed in.
More here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind