Get different output from the end of a method chain - javascript

If i have a method-chain that looks something like this:
object.value.add(1).multiply(2);
And the object is this:
var object = {
"value":1,
"add":function(x){
this.value = this.value + x;
return this;
},
"multiply":function(x){
this.value = this.value * x;
return this;
}
}
This would output:
{
"value":4,
"add":function(x){
this.value = this.value + x;
return this;
},
"multiply":function(x){
this.value = this.value * x;
return this;
}
}
But i want it to output:
4
Is this possible?
And i don't want to make another method for the output, i want the "multiply" method (and the "add" method) to multiply the entire object if it's not the last in the method-chain (so that method-chaining is possible), but when it's last i want it to output the "value" attribute.

There's no efficient way (there might not even be a way) for the method to know if it is the last member of the chain.
Why not this?
object.add(1).multiply(2).value
You could also leverage valueOf in very specific scenarios, but it cannot be leveraged as a general purpose strategy to that end.
var object = {
"value":1,
"add":function(x){
this.value = this.value + x;
return this;
},
"multiply":function(x){
this.value = this.value * x;
return this;
},
valueOf: function () { return this.value; }
};
console.log(object.add(4).multiply(2) / 2); //5

Related

"Undefined" in the end of the accumulator.value()

I ran into the problem of the value misplacement in the constructor function method this.result. I do not understand why I'm get the result of the end of the function - undefined...
Tell me please, what is forgotten to include in the function :(
function Accumulator(startingValue) {
this.startingValue = startingValue;
this.read = function() {
this.a = +prompt('Your digit: ', '');
};
this.value = function() {
this.value += this.a;
};
this.result = function() {
return this.value + this.startingValue;
}
}
var accumulator = new Accumulator(1); // starting value 1
accumulator.read(); // sum prompt with current value
accumulator.read(); // sum current prompt with previous prompt and current value
console.log( accumulator.result() ); // display sum result
If .value is supposed to be an integer, don't define it as a function :-)
I think you should drop .value(), .startingValue and .a and just use .value everywhere. Put the summation directly into the read method. Simplify to:
function Accumulator(startingValue) {
this.value = startingValue;
this.read = function() {
// the temporary variable might be unnecessary but I left it in for verbosity
const a = +prompt('Your digit: ', '');
this.value += a;
};
this.result = function() {
return this.value;
};
}
var accumulator = new Accumulator(1); // starting value 1
accumulator.read(); // add prompt to current value
accumulator.read(); // add another prompt to current value
console.log( accumulator.result() ); // display sum by calling result() method
You might also want to define the methods on the prototype:
function Accumulator(startingValue) {
this.value = startingValue;
}
Accumulator.prototype.read = function() {
this.value += +prompt('Your digit: ', '');
};
Accumulator.prototype.result = function() {
return this.value;
};
and even use modern class syntax, as #ArtificialBug suggested:
class Accumulator {
constructor(startingValue) {
this.value = startingValue;
}
read() {
this.value += parseInt(prompt('Your digit: ', ''), 10);
}
result() {
return this.value;
}
}
There are two problems
this.value = function() {
this.value += this.a; //this.value is a function
};
and
console.log( accumulator.value ); // accumulator value is a function which needs to be invoked
Make it
function Accumulator(startingValue) {
this.startingValue = startingValue;
this.read = function() {
this.a = (this.a || this.startingValue ) + +prompt('Your digit: ', '');//initialize and add the prompted value
};
this.value = function() {
return this.a; //simply return the value
};
this.result = function() {
return this.a + this.startingValue; //this.a instead of this.value
}
}
var accumulator = new Accumulator(1);
accumulator.read();
accumulator.read();
console.log( accumulator.value() ); // invoke the method

How to chain in javascript yet get value in between

ok weird title, I know. However the question is simple. In a class I want to be able to do these two things:
invoice.getAmount(); // returns 1000
and
invoice.getAmount().asCurrency(); // returns $1000.00
I can do either, just don't know how to get both to work.
What I have for now for the second idea:
getAmount() {
this._temp = this.amount;
return this;
}
asCurrency(){
if(this._temp){
return "$" + this._temp + ".00";
}
}
That's an ugly copy of what I really have but the concept is represented...
Any idea?
Thanks
Trick is to use the valueOf() method.
class Invoice {
constructor(value) {
this.value = value;
}
getAmount() {
return {
valueOf: _ => this.value,
asCurrency: _ => '$' + this.value
}
}
}
const i = new Invoice(150);
console.log(i.getAmount() + 10); // 160
console.log(i.getAmount().asCurrency()); // '$150'
You can use Number.prototype.toLocaleString():
function getAmount() {
return 1000;
}
var result = getAmount().toLocaleString('en-EN', {style: 'currency', currency: 'USD'});
console.log(result);
You can override a few built-ins (toString() and valueOf()) on the Invoice.prototype like so:
function Invoice(amount) {
this.amount = amount;
}
Invoice.prototype.toString =
Invoice.prototype.valueOf = function valueOf() {
return this.value;
};
Invoice.prototype.getAmount = function getAmount() {
this.value = this.amount;
return this;
};
Invoice.prototype.asCurrency = function asCurrency() {
this.value = '$' + this.value.toFixed(2);
return this;
};
var invoice = new Invoice(1000);
console.log(Number(invoice.getAmount()));
console.log(String(invoice.getAmount().asCurrency()));
// or more subtly
console.log(invoice.getAmount() + 0);
console.log(invoice.getAmount().asCurrency() + '');
Or using ES6 class:
class Invoice {
constructor(amount) {
this.amount = amount;
}
toString() {
return this.value;
}
valueOf() {
return this.value;
}
getAmount() {
this.value = this.amount;
return this;
}
asCurrency() {
this.value = '$' + this.value.toFixed(2);
return this;
}
}
var invoice = new Invoice(1000);
console.log(Number(invoice.getAmount()));
console.log(String(invoice.getAmount().asCurrency()));
// or more subtly
console.log(invoice.getAmount() + 0);
console.log(invoice.getAmount().asCurrency() + '');
Remember that getAmount is returning a number.
Thus, there is no way to chain asCurrency on the return value of getAmount (without using valueOf) unless asCurrency exists on the Number prototype.
If you wanted to keep all this composed in your class without modifying the Number prototype, you need to either use valueOf (best solution), or make your return value of getAmount your class instance so that you can chain it with asCurrency.

How to create object using object.create?

I have the following code in a separate file that is referenced with tags
function _TEST()
{
var val;
this.get = function(x)
{
return val;
}
this.prop = 'testing';
this.set = function(x)
{
val = x
return val;
}
this.exp = function(x)
{
function meth(x)
{
return 'I am a private '+x;
}
return meth(x);
}
}
Now in the head section of the main page I have
var tst = new _TEST();
window.onload = function()
{
tst.set('Hello')
alert(tst.get());
var tst2 = Object.create(_TEST.prototype);
tst2.prop = "testing"; // the only property that shows up for tst2 below
var str = '';
for(var x in tst)
{
str += x+" : "+tst[x]+"\n";
}
str += "\n\ntst2:\n"
for(var x in tst2)
{
str += x+" : "+tst2[x]+"\n";
}
alert(str)
}
The output from the call to alert is:
get : function (x) {
return val;
}
prop : testing
set : function (x) {
val = x;
return val;
}
exp : function (x) {
function meth(x) {
return "I am a private " + x;
}
return meth(x);
}
tst2:
prop : testing
As I understand it Object.create is suppose to create an object instande that inherits from the prototype.
but tst2 has none of those. What am I doing wrong here?
This is being tested in Firefox 12.0 on Mac OSX and I am not sure what version of javascript it uses. I am
Using O'Reillies Javascript: the Definitive Guide (rhino book) to increase my knowledge of objects and related
code
Edit:
I figured it out:
it works with
var tst2 = Object.create(tst);
Your code has not added any properties to the _TEST.prototype. The _TEST function adds properties directly to each instance created when a new _TEST() call is made. That has nothing to do with the prototype.

Knockout: Combining 2 custom bindings for digits - Financial data

good Day
I found the following two fiddles that does exactly what I want:
The first Fiddle gives me decimal notation.
The second Fiddle gives me digital grouping of numbers.
My Question: How do I combine both of them into one such that I can just use it like this:
<b data-bind="commaDecimalFormatter: myNumber">This will output both demical notation and digital grouping</b>
====================================================================================================================================================================
Fiddle 1 code:
// Formatting Functions
function formatWithComma(x, precision, seperator) {
var options = {
precision: precision || 2,
seperator: seperator || '.'
}
var formatted = parseFloat(x,10).toFixed( options.precision );
var regex = new RegExp(
'^(\\d+)[^\\d](\\d{' + options.precision + '})$');
formatted = formatted.replace(
regex, '$1' + options.seperator + '$2');
return formatted;
}
function reverseFormat(x, precision, seperator) {
var options = {
precision: precision || 2,
seperator: seperator || ','
}
var regex = new RegExp(
'^(\\d+)[^\\d](\\d+)$');
var formatted = x.replace(regex, '$1.$2');
return parseFloat( formatted );
}
// END: Formatting Functions
// Custom Binding - place this in a seperate .js file and reference it in your html
ko.bindingHandlers.commaDecimalFormatter = {
init: function(element, valueAccessor) {
var observable = valueAccessor();
var interceptor = ko.computed({
read: function() {
return formatWithComma( observable() );
},
write: function(newValue) {
observable( reverseFormat(newValue) );
}
});
if( element.tagName == 'INPUT' )
ko.applyBindingsToNode( element , {
value: interceptor
} );
else
ko.applyBindingsToNode( element , {
text: interceptor
} );
}
}
// this is your viewmodel
var vm = {
myNumber: ko.observable(100000)
}
// when the DOM is ready, call ko.applyBindings with your viewmodel
$(function() {
ko.applyBindings(vm);
});
FIDDLE 2 Code:
(function(){
var format = function(value) {
toks = value.toFixed(2).replace('-', '').split('.');
var display = '$' + $.map(toks[0].split('').reverse(), function(elm, i) {
return [(i % 3 === 0 && i > 0 ? ',' : ''), elm];
}).reverse().join('') + '.' + toks[1];
return value < 0 ? '-' + display : display;
};
ko.subscribable.fn.money = function() {
var target = this;
var writeTarget = function(value) {
var stripped=value
.replace(/[^0-9.-]/g, '');
target(parseFloat(stripped));
};
var result = ko.computed({
read: function() {
return target();
},
write: writeTarget
});
result.formatted = ko.computed({
read: function() {
return format(target());
},
write: writeTarget
});
result.isNegative = ko.computed(function(){
return target()<0;
});
return result;
};
})();
//Wire it up
$(function() {
var viewModel = {
Cash: ko.observable(1000000).money(),
};
viewModel.Total = ko.computed(function() {
return this.Cash();
}, viewModel).money();
ko.applyBindings(viewModel);
});
I cannot combine the two functions. Try the following, since it does what you want: Both Decimal notation and Digit grouping:
JS:
function formatPrice(price) {
return price.reverse().replace(/((?:\d{2})\d)/g, '$1 ').reverse();
}
// Need to extend String prototype for convinience
String.prototype.reverse = function() {
return this.split('').reverse().join('');
}
$('.myNumber').each(function(){
$(this).html(formatPrice($(this).html()));
});
See Fiddle
NOTE: You need to refresh the browser everytime for the jquery to format the output value(Read Only) into digit grouping...That is of course when you enter a new value into the editor screen(first field) and you don't see the digit grouping updated
I'd like to provide an alternative solution. You could also create a custom binding handler that does what you want (which would use the syntax you originally proposed).
ko.bindingHandlers. commaDecimalFormatter = {
update: function(element, valueAccessor, allValuesAccessor) {
// This gets the current value of the observable from your model
var value = ko.utils.unwrapObservable(valueAccessor());
// Manipulate `value` as desired using the bodies of the functions you mentioned
// Note: You don't want to use a global function, so actually take the bodies
// and put it here. Plain old JS :)
...
// Set the value on the element
jQuery(element).text(value);
}
};

Getter in object isn't returning a value Javascript

I have a problem with return a value from an object.
my object looks like this.
function XYZ(date, startT)
{
var _date=date;
var _startT=startT;
this.get_date = function() {
return _date;
};
this.set_date = function(value) {
_date=value;
};
this.get_startT = function() {
return _startT;
};
this.set_startT = function(value) {
_startT=value;
};
this.toString()
return (_date + " " _startT);
}
then i create an Array like this
jsData[0] =new XYZ("2012-11-11","8:00");
jsData[1] = new XYZ("2012-03-03","8:00");
when i want to use get_date method it didn't return me the value but the get_startT method works fine.
When i show object with .toString method it also show me full object
Please help.
It works if you fix all the syntax errors:
function XYZ(date, startT) {
var _date=date;
var _startT=startT;
this.get_date = function() {
return _date;
};
this.set_date = function(value) {
_date=value;
};
this.get_startT = function() {
return _startT;
};
this.set_startT = function(value) {
_startT=value;
};
}
var jsData = [];
jsData[0] = new XYZ("2012-11-11","8:00");
jsData[1] = new XYZ("2012-03-03","8:00");
display("jsData[0].get_date() = " + jsData[0].get_date());
Output:
jsData[0].get_date() = 2012-11-11
Live Copy | Source
Other than obvious typos, here's what I did:
Put { and } around the function body.
Removed the this.toString() which was non-functional (a no-op, as you didn't store the result anywhere).
Removed the return at the end, because returning a string primitive out of a constructor function is another no-op.
Declared jsData.
Initialized jsData.
You appear to be missing a opening bracket { after
function XYZ(date, startT)
And one at the end of your code. (})
Try adding methods to the function prototype like this:
function XYZ(date, startT) {
this._date = date;
this._startT = startT;
}
XYZ.prototype.get_date = function() {
return this._date;
}
XYZ.prototype.set_date = function(value) {
this._date = value;
}
XYZ.prototype.get_startT = function() {
return this._startT;
}
XYZ.prototype.set_startT = function(value) {
this._startT = value;
}
XYZ.prototype.toString = function() {
return this._date + " " + this._startT;
}
var myXYZ = new XYZ("2012-11-11","8:00");
myXYZ.toString(); // "2012-11-11 8:00"
I tested that in the console and it outputs the final string correctly.

Categories

Resources