Method chaining with Javascript - Plus Minus Question - javascript

I got a code challenge that create a plus-minus functions using method chaining. i have created the code as follows but it eventually failed when it comes to the output rendering
like plus(3).minus(2).value() and minus(3).minus(3).value() kind of method invoking
code as follows
function plus(valuez)
{
this.valuez = this.valuez+ valuez;
function value{
return valuez
}
plus.minus = minus;
plus.value = value;
plus.plus = this;
return this;
}
function minus(valuez)
{
this.valuez = this.v+ valuez;
function value(){
return valuez
}
minus.plus = plus;
minus.minus = this
minus.value = value;
return this;
}
expected output is
1 and 6 but I only get the printed last number entered. how can I resolve this?

class Box {
constructor(v) { this._value = v }
plus(v) { this._value += v; return this; }
minus(v) { this._value -= v; return this; }
value() { return this._value; }
}
function plus(v) { return new Box(v) }
function minus(v) { return new Box(-v) }
console.log("plus(3).minus(2).value()", plus(3).minus(2).value());
console.log("minus(3).minus(3).value()", minus(3).minus(3).value());
function plus (x) { return { _value: x, plus(y){ return plus(this._value+y) }, minus(y){ return plus(this._value-y) }, value(){ return this._value } } }
function minus(x) { return plus(-x) }
console.log("plus(3).minus(2).value()", plus(3).minus(2).value());
console.log("minus(3).minus(3).value()", minus(3).minus(3).value());
Using closure
function plus (x) { return { plus(y){ return plus(x+y) }, minus(y){ return plus(x-y) }, value(){ return x } } }
function minus(x) { return plus(-x) }
console.log("plus(3).minus(2).value()", plus(3).minus(2).value());
console.log("minus(3).minus(3).value()", minus(3).minus(3).value());

Without a constructor or class-sugar you can return an object using closed over values from the addition/subtraction method. Something like:
const { plus, val, reset } = PM();
console.log(plus().plus(3).minus(4).plus(25).plus(4).trace());
console.log(reset().minus(2).plus(33).val());
function PM() {
let values = [];
let traced = [];
const reset = () => {
values = [];
traced = [];
return ret;
};
const add = value => {
const calc = +(values[values.length-1] || 0) + value;
traced.push(`${values[values.length-1] || 0}${
!value || value >= 0 ? "+" : ""}${value || 0}=${calc || 0}`);
values.push(calc || 0);
return ret;
};
const ret = {
plus: value => add(value),
minus: value => add(-value),
val: () => values,
trace: () => traced,
reset,
};
return ret;
}
Or combine this with an embedded constructor

Related

how to prevent calling method after it has been called when dealing with javascript method chaining?

In this example I would like to call the defineX function before calling the add and value methods
class cl {
#x;
defineX(n) {
this.#x = n;
return this;
}
add(n) {
this.#x += n;
return this;
}
value() {
return this.#x;
}
}
const cObj = new cl();
console.log(cObj.defineX(3).add(5).value()); // output 8
console.log(cObj.add(3)) // should not happen
what is the best solution so I can prevent calling add before defineX method ??
also how to prevent calling the add method after it has been called for the first time ??
Don't use a single class, use multiple ones with different methods, each holding a different immutable state. It's simpler without class syntax at all though:
const cObj = {
defineX(n) {
const x = n;
return {
add(n) {
const v = x + n;
return {
value() {
return v;
}
};
}
};
}
};
console.log(cObj.defineX(3).add(5).value()); // output 8
console.log(cObj.add(3)) // error
With classes:
const cObj = {
defineX(n) {
return new Cl(n);
}
};
class Cl {
#x;
constructor(x) {
this.#x = x;
}
add(n) {
return new Result(this.#x + n);
}
}
class Result {
#v;
constructor(v) {
this.#v = v;
}
value() {
return this.#v;
}
}
Since 1) operations not allowed and 2) breaking from a chain of calls are involved, it seems to me correct way is to throw an exception whenever something wrong happens. You can always try/catch it if you know exception is a possibility.
class cl {
#x;
#defined;
#added;
defineX(n) {
this.#x = n;
this.#defined = true;
return this;
}
add(n) {
if (!this.#defined) {
throw new Error("`add` before define")
}
if (this.#added) {
throw new Error("already did `add`")
}
this.#x += n;
this.#added = true;
return this;
}
value() {
return this.#x;
}
}
const cObj = new cl();
// tests:
// console.log(cObj.defineX(3).add(5).value()); // output 8
// console.log(cObj.add(3)) // should not happen - output error
console.log(cObj.defineX(3).add(5).add(6).value()); // output error

Async version of sort function in JavaScript

Found this question Implement async/await in sort function of arrays javascript but mine is different.
I want to implement async version of the sort function. for my programming language that compiles to JavaScript called Gaiman where everything is async by default. This make the code way simpler. Some things can be really asynchronuios like reading the input from user but all functions defined in Gaiman are async even if they don't use anything that is really asynchronous.
I've implemented custom class that extend Array:
function is_function(obj) {
return typeof obj === 'function';
}
function is_promise(obj) {
return obj && is_function(obj.then);
}
class GaimanArray extends Array {
map(...args) {
function call(arr) {
return new GaimanArray(...arr);
}
const arr = super.map.apply(this, args);
const some = super.some;
const has_promise = some.call(arr, is_promise);
if (has_promise) {
return Promise.all(arr).then(call);
} else {
return call(arr);
}
}
forEach(...args) {
return this.map(...args);
}
filter(fn, ctx) {
const filter = super.filter;
function call(arr) {
return new GaimanArray(...filter.call(arr, x => x));
}
const items = this.map(fn, ctx);
if (is_promise(items)) {
return items.then(arr => {
return call(arr);
});
} else {
return call(items);
}
}
reduce(fn, init) {
return super.reduce.call(this, function(acc, ...args) {
if (is_promise(acc)) {
return acc.then(acc => {
return fn(acc, ...args);
});
} else {
return fn(acc, ...args);
}
}, init);
}
sort() {
}
some(fn, ctx) {
const some = super.some;
return this.mapWithCallback(fn, (arr) => {
return some.call(arr, x => x);
}, ctx);
}
every(fn, ctx) {
const every = super.every;
return this.mapWithCallback(fn, (arr) => {
return every.call(arr, x => x);
}, ctx);
}
find(fn, ctx) {
return this.mapWithCallback(fn, (arr) => {
const index = arr.findIndex(x => x);
return this[index];
}, ctx);
}
flatMap(fn, ...args) {
return this.map(...args).flat();
}
mapWithCallback(fn, callback, ctx) {
const items = this.map(fn, ctx);
if (is_promise(items)) {
return items.then(arr => {
return callback(arr);
});
} else {
return callback(items);
}
}
}
The implementation of methods in my array actually makes the promise-based function optional, this is a leftover implementation when I was modifying Array.prototype but it gives problems with some other library that was executing args.some(is_promise).
I think that I can't use Schwartzian transform because I can't get value for each item, my comparison function needs to be really async.
So how can I implement async sort in JavaScript? Every method is working with async functions except I have no idea how to implement sort.
I've created working code based on Rosseta Code:
// based on: https://rosettacode.org/wiki/Sorting_algorithms/Merge_sort#JavaScript
async function mergeSort(array, fn) {
if (array.length <= 1) {
return array;
}
const mid = Math.floor(array.length / 2),
left = array.slice(0, mid), right = array.slice(mid);
await mergeSort(left, fn);
await mergeSort(right, fn);
let ia = 0, il = 0, ir = 0;
while (il < left.length && ir < right.length) {
array[ia++] = (await fn(left[il], right[ir]) <= 0) ? left[il++] : right[ir++];
}
while (il < left.length) {
array[ia++] = left[il++];
}
while (ir < right.length) {
array[ia++] = right[ir++];
}
return array;
}

How to get the result of executing a function inside it, make a transformation and return

The Add function is called by the user in the external environment. It is necessary that the called Add function is executed and the resulting value is converted to a number and returned as a response from the called Add function to the external environment.
function Ext() {
let cs = 0;
function pars(fn) {
let newFn = fn.bind(null);
function cal(...num) {
newFn = newFn.bind(null, ...num);
return cal;
}
cal.toString = () => newFn();
return (...num) => {
newFn = fn.bind(null);
return cal(...num);
};
}
const _add = pars((...num) => {
num.forEach((item) => { cs += item; });
return num.reduce((a, b) => a + b);
});
return {
add: function add(...num) {
if ([...num].length === 0) return add;
return _add(...num);
}
/*
add: function(...num) {
function add(...num) {
if ([...num].length === 0) return add;
var promise = new Promise(function(resolve, reject) {
let result = _add(...num);
resolve(result);
});
return promise;
}
add(...num).then(function(result) { Number(result) });
},
*/
}
}
const ext = Ext();
console.log(ext.add()); //function
console.log(ext.add(1)); //1
console.log(ext.add(3, 1)()(3)); //7
console.log(typeof ext.add(1)); //function
let one = ext.add(1);
console.log(one === 1); //false
console.log(Number(one) === 1); //true
console.log(typeof one) //function
console.log(typeof 1) //number
That is, the add function externally returns a number, but it is a function by type. It is necessary that the function ultimately return exactly the number: console.log (typeof ext.add (1)) // Number P. S. The commented code in the question is an attempt to make the function return exactly the number.

How to replace style property with proxy

I have code like this in my unit tests for jQuery Terminal:
// https://github.com/tmpvar/jsdom/issues/135
Object.defineProperties(window.HTMLElement.prototype, {
offsetLeft: {
get: function() { return parseFloat(window.getComputedStyle(this).marginLeft) || 0; }
},
offsetTop: {
get: function() { return parseFloat(window.getComputedStyle(this).marginTop) || 0; }
},
offsetHeight: {
get: function() { return parseFloat(window.getComputedStyle(this).height) || 0; }
},
offsetWidth: {
get: function() { return parseFloat(window.getComputedStyle(this).width) || 0; }
},
// this will test if setting 1ch change value to 1ch which don't work in jsdom used by jest
style: {
get: function() {
if (this.__style) {
return this.__style;
}
var self = this;
var attr = {};
function set_style_attr() {
var str = Object.keys(attr).map((key) => `${key}: ${attr[key]}`).join(';') + ';';
self.setAttribute('style', str);
}
var mapping = {
backgroundClip: 'background-clip',
className: 'class'
};
var reversed_mapping = {};
Object.keys(mapping).forEach(key => {
reversed_mapping[mapping[key]] = key;
});
return this.__style = new Proxy({}, {
set: function(target, name, value) {
name = mapping[name] || name;
if (!value) {
delete target[name];
delete attr[name];
} else {
attr[name] = target[name] = value;
}
set_style_attr();
return true;
},
get: function(target, name) {
if (name === 'setProperty') {
return function(name, value) {
attr[name] = target[name] = value;
set_style_attr();
};
} else {
return target[name];
}
},
deleteProperty: function(target, name) {
name = reversed_mapping[name] || name;
delete target[name];
delete attr[name];
set_style_attr();
}
});
}
}
});
It works for 1ch attribute in my tests that look like this:
it('should handle wider characters without formatting', function() {
var input = 'ターミナルウィンドウは黒[[;;]です]';
var string = $.terminal.format(input, {char_width: 7});
expect(string).toEqual('<span style="width: 24ch"><span style="widt'+
'h: 24ch">ターミナルウィンドウは黒</span></span'+
'><span style="width: 4ch" data-text="です">'+
'<span style="width: 4ch">です</span></span>');
});
If I don't use my Proxy I got width in pixels, because I have code like this to check if ch is supported in my code:
var agent = window.navigator.userAgent;
var is_IE = /MSIE|Trident/.test(agent) || /rv:11.0/i.test(agent);
var is_IEMobile = /IEMobile/.test(agent);
// -------------------------------------------------------------------------
var is_ch_unit_supported = (function() {
if (is_IE && !is_IEMobile) {
return false;
}
var div = document.createElement('div');
div.style.width = '1ch';
return div.style.width === '1ch';
})();
The problem is when I want to check the style property to get some value, like this test:
it('should find inside formatting', function() {
term.less(big_text.concat(['[[;red;]foo bar baz]']));
search('bar');
var spans = term.find('[data-index="0"] > div:first-child span');
['foo ', 'bar', ' baz'].forEach(function(string, i) {
expect(a0(spans.eq(i).text())).toEqual(string);
});
[true, false, true].forEach(function(check, i) {
console.log(spans.get(i).style.getPropertyValue('color'));
expect([i, !!spans.get(i).attr('style').match(/color:\s*red/)]).toEqual([i, check]);
});
});
I've tried:
spans.get(i).style.getPropertyValue('color')
This return error that's not a function and
spans.get(i).attr('style')
is undefined. This also don't work
spans.get(i).getAttribute('style')
which should be the same and the one before.
Is there a way to have ch unit support check work but in same way getting values from style attribute as well?
I'm using jest framework that use jsDom I running my tests from Node.
I've tried to create getPropertyValue function in get trap for the proxy but I don't know how to get original function so I can call it.
So to sum up, I need solution in jsDOM that allow to set width to 1ch and get that value back (so my code don't change), and that should work when creating new HTMLElement in DOM and get it's value out of, It don't need to be style object with props it can be style property as string. Alternative solution is to test if ch unit is supported that will work in jsDOM.
I've solved the issue by temporarily disabling getter when accessing properties:
(function() {
var style_descriptor = Object.getOwnPropertyDescriptor(window.HTMLElement.prototype, 'style');
Object.defineProperties(window.HTMLElement.prototype, {
offsetLeft: {
get: function() { return parseFloat(window.getComputedStyle(this).marginLeft) || 0; }
},
offsetTop: {
get: function() { return parseFloat(window.getComputedStyle(this).marginTop) || 0; }
},
offsetHeight: {
get: function() { return parseFloat(window.getComputedStyle(this).height) || 0; }
},
offsetWidth: {
get: function() { return parseFloat(window.getComputedStyle(this).width) || 0; }
},
// this will test if setting 1ch change value to 1ch which don't work in jsdom used by jest
style: {
get: function getter() {
if (this.__style) {
return this.__style;
}
var self = this;
var attr = {};
function set_style_attr() {
var str = Object.keys(attr).map((key) => `${key}: ${attr[key]}`).join(';') + ';';
self.setAttribute('style', str);
}
var mapping = {
backgroundClip: 'background-clip',
className: 'class'
};
var reversed_mapping = {};
Object.keys(mapping).forEach(key => {
reversed_mapping[mapping[key]] = key;
});
function disable(fn) {
// temporary disable proxy
Object.defineProperty(window.HTMLElement.prototype, "style", style_descriptor);
var ret = fn();
Object.defineProperty(window.HTMLElement.prototype, "style", {
get: getter
});
return ret;
}
return this.__style = new Proxy({}, {
set: function(target, name, value) {
name = mapping[name] || name;
if (!value) {
delete target[name];
delete attr[name];
} else {
attr[name] = target[name] = value;
}
set_style_attr();
disable(function() {
self.style[name] = name;
});
return true;
},
get: function(target, name) {
if (name === 'setProperty') {
return function(name, value) {
attr[name] = target[name] = value;
set_style_attr();
};
} else if (target[name]) {
return target[name];
} else {
return disable(function() {
return self.style[name];
});
}
},
deleteProperty: function(target, name) {
name = reversed_mapping[name] || name;
delete target[name];
delete attr[name];
disable(function() {
delete self.style[name];
});
set_style_attr();
}
});
}
}
});
})();

Chain functions in JavaScript

Is there a way to chain functions in JavaScript so when last function in chain is called we take into consideration all function in chain that was specified.
Basically what I am trying to do is the same thing express-validator
does:
Something like this:
check('password').passwordValidator().optional();
I want to be able to call
check('password').passwordValidator();
and
check('password').passwordValidator().optional();
So you're looking for a sort of builder pattern? You can do that like this:
class Foo {
_passwordValidator = false;
_optional = false;
passwordValidator() {
this._passwordValidator = true;
return this;
}
optional() {
this._optional = true;
return this;
}
doThing() {
if (this._optional) { /* ... */ }
if (this._passwordValidator) { /* ... */ }
}
}
const foo = new Foo().passwordValidator().optional();
foo.doThing();
Edit: to more directly answer your question, there is no way to wait to do something until the current chain of method calls is done; you have to call a method like doThing() in the example to signal that you actually want to do the thing now.
I ended up using what #coolreader18 suggested.
That was exactly what I was looking for.
function func(val) {
this._optional = false;
this._check = false;
const doStaff = (message = 'Doing staff') => {
console.log(message);
return;
};
return {
check: function(n) {
this._check = true;
return this;
},
optional: function(n) {
this._check = false;
this._optional = true;
return this;
},
exec: function() {
if (this._check) doStaff();
if (this._optional) doStaff('Maybe not');
}
}
}
func().check().optional().exec();
var Obj = {
result: 0,
addNumber: function(a, b) {
this.result = a + b;
return this;
},
multiplyNumber: function(a) {
this.result = this.result * a;
return this;
},
divideNumber: function(a) {
this.result = this.result / a;
return this;
}
}
Obj.addNumber(10, 20).multiplyNumber(10).divideNumber(10);
link => https://medium.com/technofunnel/javascript-function-chaining-8b2fbef76f7f
Calling a chained method of express-validator returns a middleware function, and as functions can have properties you can call a method on that returned function, which returns a new function with methods and so on. Chaining functions is quite easy:
const chain = (pairs, fn = el => el) => {
for(const [key, method] of pairs)
fn[key] = (...opt) => chain(pairs, method(fn)(...opt));
return fn;
};
const math = chain([
["add", prev => a => b => prev(b) + a],
["mul", prev => a => b => prev(b) * a]
]);
console.log(
(math.add(5).mul(3).add(3))(5)
);
This solution is inspierd by React setState:
function pipe/*<U>*/(val/*: U*/) {
return {
case: function (condition/*: boolean*/, value/*: U | ((prop: U) => U)*/) {
if (condition) {
if (value instanceof Function) {
return pipe(value(val));
} else {
return pipe(value);
}
} else {
return pipe(val);
}
},
valueOf: function () {
return val;
},
};
}
const result = pipe(2)
.case(false, 3)
.case(true, (current) => current + 2)
.case(false, 4)
.valueOf();
console.log(result) // 4

Categories

Resources