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

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

Related

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.

Using method in javascript

Supouse I have the next method to insert a value in a cell of a table:
var objeto = {
row: function(rowId){
return {
cell: function(cellClass){
return {
set: function(val){
document.querySelector(rowId+' '+cellClass).innerHTML = val;
}
}
//Or just return the value
}
}
}
};
I know to insert the value, I need use:
objeto.row('#rowid').cell('.cellclass').set('hello');
But If I want to get the cell value using:
var data = objeto.row('#rowid').cell('.cellclass');
What's the method I need to use?
You can use the following structure:
var objeto2 = {
row: function(rowId){
return {
cell: function(cellClass){
return {
value: function(val){
if (val) {
document.querySelector(rowId + ' ' + cellClass).innerHTML = val;
} else {
return document.querySelector(rowId + ' ' + cellClass).innerHTML;
}
}
}
}
}
}
};
objeto.row('#rowid').cell('.cellclass').value('hello'); // set value
objeto.row('#rowid').cell('.cellclass').value(); // get value
The problem is return type of any function is fixed. That means if it returns object always object will be return from that function. What you want to do is you try to benefit from polymorpholism but its cannot be done in such way.
var objeto = {
row: function(rowId){
return {
cell: function(cellClass,newValue){
this.set = function (newValue){
if(typeof newValue != "undefined"){
document.querySelector(rowId+' '+cellClass).innerHTML = val;
}
}
this.set(newValue);
return document.querySelector(rowId+' '+cellClass).innerHTML;
}
//Or just return the value
}
}
}
};
So you can use
var currentValue = objeto.row('#rowid').cell('.cellclass','hello');
or
var currentValue = objeto.row('#rowid').cell('.cellclass');

Writing a function to set some but not necessarily all parameters in another function

I had a coding interview test that asked the following question which I was not able to fully solve. I'm wondering the best way to do this following my approach -- also sorry this is long.
You are given a function to read in like this (not necessarily 2 parameters):
function add(a, b) {
return a + b;
}
The objective is to create a function to initialize some of those variables and again call the function to perform the calculation like, function setParam(func, params). To use this you would do the following:
_add = setParam(add, {b:9})
_add(10) // should return 19
My solution was to parse the function to see how many parameters there are, then set them using the given parameters but since I barely know javascript I was never able to actually return a function with only some variables set and others still undefined.
(attempt at solution)
function setParam(func, params) {
// varray is an array of the the varriables from the function, func
// ie varray = [a,b] in this test
var varray = /function[^\(]*\(([^\)]*)\)/.exec(func.toString())[1].split(',');
//creates an array, paramset, that has the variables in func defined
//where possible
// ex paramset = [a,9] if only b was set
var paramsset = []
for (i = 0; i < varray.length; i++) {
if (typeof(params[varray[i]]) == "undefined"){
paramsset[i] = varray[i];
} else {
paramsset[i] = params[varray[i]];
}
}
//////
// need to modify existing function and return with added parameters
// where I'm stuck as this doesn't work.
newfunc = (function(){
var _func = func;
return function() {
return _func.apply(this, paramsset);
}
})();
newfunc()
}
I'm sure I'm not doing this the correct way, but any help would be appreciated.
I'm certainly not advocating to go towards that solution, but I still implemented something to follow your initial's API design for fun. The signatures weak map is necessary in order to preserve the initial function's signature so that we can call setParams again on partially applied functions.
var setParams = (function () {
var signatures = new WeakMap();
return function (fn, paramsToApply) {
var signature = signatureOf(fn), newFn;
validateParams(paramsToApply, signature.params);
newFn = function () {
var params = appliedParamsFrom(arguments, paramsToApply, signature.indexes);
return fn.apply(this, params);
};
signatures.set(newFn, signature);
return newFn;
};
function signatureOf(fn) {
return signatures.has(fn)?
signatures.get(fn) :
parseSignatureOf(fn);
}
function parseSignatureOf(fn) {
return String(fn)
.match(/function.*?\((.*?)\)/)[1]
.replace(/\s+/g, '')
.split(',')
.reduce(function (r, param, index) {
r.indexes[param] = index;
r.params.push(param);
return r;
}, { indexes: {}, params: [] });
}
function validateParams(paramsToApply, actualParams) {
Object.keys(paramsToApply).forEach(function (param) {
if (actualParams.indexOf(param) == -1) throw new Error("parameter '" + param + "' could not be found in the function's signature which is: 'function (" + actualParams + ")'");
});
}
function appliedParamsFrom(args, paramsToApply, paramsIndex) {
var appliedParams = [],
usedIndexes = [],
argsIndex = 0,
argsLen = args.length,
argSpotIndex = 0;
Object.keys(paramsToApply).forEach(function (param) {
var index = paramsIndex[param];
appliedParams[index] = paramsToApply[param];
usedIndexes.push(index);
});
while (argsIndex < argsLen) {
if (usedIndexes.indexOf(argSpotIndex) == -1) {
appliedParams[argSpotIndex] = args[argsIndex++];
}
++argSpotIndex;
}
return appliedParams;
}
})();
function add(a, b) { return a + b; }
var addTo9 = setParams(add, { b: 9 });
var add10To9 = setParams(addTo9, { a: 10 });
document.write(addTo9(10) + ', ' + add10To9());
Now, note that JavaScript comes with the Function.prototype.bind function which allows to perform in-order partial function application. The first parameter to bind has nothing to do with arguments, it's to bind the this value.
function add(a, b) { return a + b; }
var addTo9 = add.bind(null, 9);
document.write(addTo9(10));
And finally, an implementation with a placholder if you need one:
var partial = (function (undefined) {
var PLACEHOLDER = {};
function partial(fn, partialArgs) {
return function () {
return fn.apply(this, applyPartialArgs(arguments, partialArgs));
};
}
Object.defineProperty(partial, 'PLACEHOLDER', {
get: function () { return PLACEHOLDER; }
});
return partial;
function applyPartialArgs(args, partialArgs) {
var appliedArgs = partialArgs.map(function (arg) {
return arg === PLACEHOLDER? undefined : arg;
}),
partialArgsLen = partialArgs.length,
argsLen = args.length,
argsIndex = 0,
argSpotIndex = 0;
while (argsIndex < argsLen) {
if (
partialArgs[argSpotIndex] === PLACEHOLDER ||
argSpotIndex >= partialArgsLen
) {
appliedArgs[argSpotIndex] = args[argsIndex++];
}
++argSpotIndex;
}
return appliedArgs;
}
})();
function add(a, b, c, d) {
return a + b + c + d;
}
var _ = partial.PLACEHOLDER;
var addTo9 = partial(add, [_, 5, _, 4]);
document.write(addTo9(5, 5));
I'm guessing that they might have been testing for knowledge of partial application. (not currying)
Edit: Edited based upon your comments. This is Crockford's curry function straight from his book.
function add(a, b) {
return a + b;
}
if (!Function.prototype.partial) {
Function.prototype.partial = function() {
var slice = Array.prototype.slice,
args = new Array(arguments.length),
that = this;
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i];
}
return function() {
return that.apply(null, args.concat(slice.apply(arguments)));
}
};
}
var example = add.partial(4);
console.log(example(10)); // output 14
console.log(example(20)); // output 24
var example = adder(4) assigns example to be function with a closure with a (in this case 4). When example is called like in the console.log, it will in effect be returning "the value of a when example was assigned, plus this new number."
Walkthrough of the partial() function:
Converts arguments to an array
returns a function gets passed the arguments given, which can be called later. It has a closure with the previously assigned arguments.

Why are my properties assigning incorrectly?

I created an ObservablePropertyList which is supposed to execute a callback when a property changes. The implementation is:
function ObservablePropertyList(nameCallbackCollection) {
var propertyList = {};
for (var index in nameCallbackCollection) {
var private_value = {};
propertyList["get_" + index] = function () { return private_value; }
propertyList["set_" + index] = function (value) {
// Set the value
private_value = value;
// Invoke the callback
nameCallbackCollection[index](value);
}
}
return propertyList;
}
And here's a quick test demonstration:
var boundProperties = BoundPropertyList({
TheTime: function (value) {
$('#thetime').text(value);
},
TheDate: function (value) {
$('#thedate').text(value);
}
});
var number = 0;
setInterval(function () {
boundProperties.set_TheTime(new Date());
boundProperties.set_TheDate(number++);
}, 500);
For some reason though, the properties are not being assigned correctly or something. That is, calling set_TheTime for some reason executes the callback for set_TheDate, almost as though it were binding everything to only the last item in the list. I can't for the life of me figure out what I'm doing wrong.
When using loops like that you need to wrap it in an enclosure
function ObservablePropertyList(nameCallbackCollection) {
var propertyList = {};
for (var index in nameCallbackCollection) {
(function(target){
var private_value = {};
propertyList["get_" + index] = function () { return private_value; }
propertyList["set_" + index] = function (value) {
// Set the value
private_value = value;
// Invoke the callback
target(value);
}
})(nameCallbackCollection[index]);
}
return propertyList;
}
You need to create a closure in order for each iteration of the for loop to have its own private_variable object. Otherwise, each iteration just overwrites the previous (since private_variable is hoisted to the top of its scope). I'd set it up like this:
var ObservablePropertyList = (function () {
"use strict";
var handleAccess = function (propList, key, callback) {
var privValue = {};
propList["get_" + key] = function () {
return privValue;
};
propList["set_" + key] = function (value) {
// Set the value
privValue = value;
// Invoke the callback
callback(value);
};
};
return function (coll) {
var propertyList = {}, index;
for (index in coll) {
handleAccess(propertyList, index, coll[index]);
}
return propertyList;
};
}());
var boundProperties = ObservablePropertyList({
TheTime: function (value) {
$('#thetime').text(value);
},
TheDate: function (value) {
$('#thedate').text(value);
}
}), number = 0;
setInterval(function () {
boundProperties.set_TheTime(new Date());
boundProperties.set_TheDate(number++);
}, 500);
DEMO: http://jsfiddle.net/PXHDT/

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