When I run solve-3 with --l=4 and --w=4, function rectangle.perimeter and rectangle.area output NaN. Why?
To me it seemed like the integers entered are being converted to strings hence why I added Number(), but that did not change anything.
File 1: rect-2.js
module.exports = function(l,w,callback) {
try {
if (l < 0 || w < 0) {
throw new Error("Rectangle dimensions should be greater than zero: l = " + l + ", and w = " + w);
}
else
callback(null, {
perimeter: function(l,w) {
return (2*(l+w));
},
area: function(l,w) {
return (l*w);
}
});
}
catch (error) {
callback(error,null);
}
}
File 2: solve-3.js
var argv = require('yargs')
.usage('Usage: node $0 --l=[number] --w=[number]')
.demand(['l','w'])
.argv;
var rect = require('./rect-2');
function solveRect(l,w) {
console.log("Solving for rectangle with length: " + l + " and width: " + w);
rect(l,w, function(err,rectangle) {
if (err) {
console.log(err);
}
else {
console.log("The area of a rectangle with length = "+l+" and width = "+w+" is "+rectangle.area());
console.log("The perimeter of a rectangle with length = "+l+" and width = "+w+" is "+rectangle.perimeter());
}
});
};
solveRect(Number(argv.l),Number(argv.w));
Look at the functions you've defined:
perimeter: function(l,w) {
return (2*(l+w));
},
You expect this function to take two arguments.
Then you call it with no arguments:
rectangle.perimeter()
The arguments you're defining are shadowing the ones in the upper scope of your rect-2 file. A simple workaround is just to remove the function arguments:
perimeter: function() {
return (2*(l+w));
},
area: function() {
return (l*w);
}
Now these two functions are said to "close over" the l and w variables present in the upper scope.
While wrapping a string in Number() will technically work in this case, note that yargs lets you specify the types of user input values on the command line, such as the .number() syntax:
var argv = require('yargs')
.number(['l','w'])
.demand(['l','w'])
Related
I am new to node js and taking a course to learn it. However, I am not able to make a simple closure property of javascript work in it. I have 2 files index.js and rectangle.js where in I am using callback to return the area & perimeter of rectangle.
index.js
var rect = require('./rectangle');
function solveRect(l,b) {
console.log("Solving for rectangle with l = " + l + "and b = " + b);
rect(l,b, (err,rectangle) => {
if(err) {
console.log("ERROR: " + err.message);
}
else {
console.log("The area of rectangle of dimensions l = "
+ l + "and b = " + b + " is " + rectangle.area());
console.log("The perimeter of rectangle of dimensions l = "
+ l + "and b = " + b + " is " + rectangle.perimeter());
}
});
console.log("This statement is after the call to rect()");
}
solveRect(2,4);
solveRect(3,5);
solveRect(0,4);
solveRect(-3,-5);
rectangle.js
module.exports = (x,y,callback) => {
if( x <= 0 || y <= 0) {
setTimeout(() =>
callback(new Error("rectangle dimensions should be greater than zero"),
null),
2000
);
}
else {
setTimeout(() =>
callback(null,
{
perimeter: (x,y) => (2*(x+y)),
area: (x,y) => (x*y)
}),
2000
);
}
}
I see that since length and breadth are already available to the callback from the outer scope, there isn't any need to pass them when we call the rectangle.area() function.
Output: I get NaN returned as area and perimeter and not the actual calculated area.
The perimiter and area functions take arguments x and y, so they use those arguments to calculate the results, not the variables inherited from the closure. Since you're not supplying any arguments when you call them in solveRect(), you're performing arithmetic on undefined, which results in NaN.
Get rid of the arguments so they'll use the closure variables.
setTimeout(() =>
callback(null,
{
perimeter: () => (2*(x+y)),
area: () => (x*y)
}),
2000
);
I'm trying to pass a function with two arguments as an argument to another function (sort of callbacks). I have one function that is unchangeble ("F"), and another that's a wrapper to the former one, and which I can code the way I like ("G"). I tried to simplify the code as much as possible, leaving just the important parts of it:
"use strict"
// this function can't be changed in any way
var F = function (a, b)
{
return new G(function (success, error)
{
var sum = a + b;
if (sum > 0)
{
// EXCEPTION: point of failure, since we can't reach G.success
success(sum);
}
else
{
// of course we'd fail here too
error(sum);
}
});
};
var G = function (f)
{
this.success = function (result)
{
console.log("The sum is positive: " + result);
}
this.error = function (result)
{
console.log("The sum is negative: " + result);
}
return f();
};
var result = F(10, 5);
Right now I am attempting to build a JavaScript library, albeit, it is very juvenile and I'm sure that it can be reworked to perform better. However, I'm currently storing some of my more common functions that I routinely use (while rendering HTML5 Canvas animations) and I have aforementioned JavaScript functions stored within their own flat file named canvasLab.js. My current structure is this:
var canvasLab = {
setCanvas: function(elem) {
if (elem == undefined) {
return Modernizr.canvas;
}
return document.getElementById(elem);
},
set2D: function(elem) {
return elem.getContext('2d');
},
... and everything works fine until I attempt to declare a function within another function:
getColorGradient: function(freqR,freqG,freqB,phaseA,phaseB,phaseC,center,width,length) {
if (center == undefined) center = 128;
if (width == undefined) width = 127;
if (length == undefined) length = 50;
colorArray=[];
frequency = 0.3;
amplitude = 127;
center = 128;
byte2Hex: function(n) {
nybHexString = '0123456789ABCDEF';
return String( nybHexString.substr( ( n >> 4 ) & 0x0F, 1 ) ) + nybHexString.substr(n & 0x0F, 1);
},
getRgb: function(r,g,b) {
return '#' + byte2Hex(r) + byte2Hex(g) + byte2Hex(b);
},
getGradientArray: function() {
for (var i=0; i<length; ++i) {
red = Math.sin(freqR * i + phaseA) * width + center;
green = Math.sin(freqG * i + phaseB) * width + center;
blue = Math.sin(freqB * i + phaseC) * width + center;
result = getRgb(red,green,blue);
this.colorArray[i] = result;
}
}
}
when I receive an 'unexpected token (' error at line 45:
byte2Hex: function(n) {
I'm sort of new to making JavaScript libraries (or Lib Objects), and I am still unsure about the best method(s) and syntax to use while developing a library. My hugest concern is that it is light weight internally, on the client's machine and in the browser. In either case, I do not understand why I cannot create a new method (i.e.: byte2Hex()) and have it instantiated through the parent object. Any criticism would surely be appreciated.
Your are defining your function as if it was in scope of an object
byte2Hex: function(n)
This line should say
byte2Hex = function(n)....
These two functions below also have the same issue
If you want to return them as methods then they should be wrapped in an object.
return {
getRgb: function(r,g,b) {
return '#' + byte2Hex(r) + byte2Hex(g) + byte2Hex(b);
},
getGradientArray: function() {//...
}
};
You also have a ton of references that are not scoped using the var statement.
To help you find, track these types of errors try pasting your code into:
http://www.jshint.com/
I have a rather simple javascipt formula:
Math.round(minMax[0] + ((minMax[1] - minMax[0]) / 2));
Value of minMax[0] is 1 and minMax[1] is 5
But for some reason i get the result 12 out of this. where i was expecting 3, now my guess is that it calculates ((minMax[1] - minMax[0]) / 2) to 2 but then adds them together as a string with the result of "1"+"2" = 12
What can i do to make javascript see this as numbers?
Update:
if i change the formula to the following then it workes, but is ugly as hell
index = Math.round(parseInt(minMax[0]) + ((parseInt(minMax[1]) - parseInt(minMax[0])) / 2));
Update 2: How min max is found, this is in Typescript
private getMinMaxIndex(parentIds: number[]): number[] {
var minIndex = 99999999;
var maxIndex = -1;
for (var k in parentIds) {
var index = this.getIndexOf(parentIds[k]);
if (index > maxIndex) maxIndex = index;
if (index < minIndex) minIndex = index;
}
return [minIndex, maxIndex];
}
...
var minMax = this.getMinMaxIndex(limitedParents);
index = Math.round(parseInt(minMax[0]) + ((parseInt(minMax[1]) - parseInt(minMax[0])) / 2));
Update 3:
private getIndexOf(id: number) {
var nodes: INode[] = this.nodes.Get();
for (var i in nodes) {
if (nodes[i].GetId() == id)
return i;
}
console.log("Unable to find parent index, for node id: " + id + " in swimlane " + this.Name + ", this should not happen and will break.");
console.log(nodes);
return null;
}
export interface INode{
GetId(): number;
...
}
export class SubmissionNode implements INode {
...
constructor(data: DiagramInputObject) {
this.data = data;
}
public GetId(): number {
return this.data.Id;
}
}
export interface DiagramInputObject {
Id: number;
...
}
Finally the DiagramInputObject in question that is how it is parsed into the code
{
Id: 1014,
UserId: 1,
Type: 0,
SwimLaneId: null,
SwimLaneName: null,
Submitted: new Date("3/9/2014 8:56:00 PM"),
ParentId: 9,
MergeId: null,
Exportable: false,
TypeData: "null",
}
private getIndexOf(id: number) {
var nodes: INode[] = this.nodes.Get();
for (var i in nodes) { // <---- PROBLEM HERE
if (nodes[i].GetId() == id)
return i;
}
console.log("Unable to find parent index, for node id: " + id + " in swimlane " + this.Name + ", this should not happen and will break.");
console.log(nodes);
return null;
}
Remember that in JavaScript, all (all!) array indexes are actually strings. A for in loop enumerates all of the keys of an object, and all keys of an object are strings. getIndexOf, then, returns a string.
You should just use a standard length-based for loop:
for(var i = 0; i < nodes.length; i++) {
/* same loop body */
}
As other people have pointed out, and i was already aware of, is that the variable is not a integer.
I was using typescript so i did not exepect this problem, to solve it have i added parseInt around the numbers to ensure it is an integer.
The wierd thing is that ((minMax[1] - minMax[0]) / 2) is calculated as a number, but where minMax[0] + ((minMax[1] - minMax[0]) / 2) is not. I can only guess that the /2 forces javascript to view the varaibles as integers, just wired that this dose not extend to minMax[0] +.
I am having trouble understanding how to return information to the first function from the second when there are multiple arguments. Now I know the following code works.
function One() {
var newVal = 0;
newVal = Too(newVal);
console.log(newVal);
}
function Too(arg) {
++arg;
return arg;
}
But what if I try to complicate things by adding arguments and a setinterval.
function One() {
var newVal = 0;
var z = 3;
var y = 3;
var x = 1;
newVal = Too(newVal);
var StopAI2 = setInterval(function () {
Too(x, y, z, newVal)
}, 100);
}
function Too(Xarg, Yarg, Zarg, newValarg) {
Xarg*Xarg;
Yarg*Yarg;
Zarg*Zarg;
++newValarg;
return newValarg;
}
I'm not sure what to do with the newVal = line of code. I only want to return the newVal not x,y,z.
This is what I think you're trying to ask:
How can I operate on the 4th argument to a function when only one argument is passed?
The answer to that question is this:
If you want to operate on the 4th argument of a function, at least 4 arguments must be passed to the function.
There are a few ways you can approach your problem differently.
#1
If there's one argument that is always necessary, make sure it's the first argument:
function Too(mandatoryArg, optionalArg1, optionalArg2) {
alert(++mandatoryArg);
if (optionalArg1) {
alert(++optionalArg1);
}
}
#2
Pass placeholder values for all the undefined or unknown arguments.
You might use null, undefined, or ''.
alert(Too(null, null, 4));
function Too(optArg1, optArg2, mandatoryArg) {
alert(++mandatoryArg);
}
#3
Make a decision based on the number of arguments:
function Too(optArg1, optArg2, optArg3) {
var numArgs = arguments.length;
if (numArgs === 1) {
alert(++optArg1);
}
if (numArgs === 3) {
alert(++optArg3);
}
}
EDIT
"Will this update a variable in the first function?"
Let's use an actual example that demonstrates something:
function one() {
var a = 0;
var b = 25;
var c = 50;
var d = -1;
d = two(a, b, c);
alert("a: " + a);
alert("b: " + b);
alert("c: " + c);
alert("d: " + d);
}
function two(a, b, c) {
++a;
++b;
++c;
if (arguments.length === 1) {
return a;
}
if (arguments.length === 3) {
return c;
}
}
Invoking one() will cause the following alerts:
a: 0
b: 25
c: 50
d: 51
Only the value of d is modified in function one().
That's because d is assigned the return value of two().
The changes to a, b, and c, inside two() have no effect on the values of a, b, and c inside one().
This would be the case even if the arguments for two() were named a, b, and c.
Here's a fiddle with the code above.
EDIT #2
Here is one way you could create functions that move a game object:
var FORWARD = 0;
var BACK = 1;
var LEFT = 2;
var RIGHT = 3;
// use an object with three values to represent a position
var pos = {
x: 0,
y: 0,
z: 0
};
pos = moveObject(pos, FORWARD);
printPosition(pos);
pos = moveObject(pos, LEFT);
printPosition(pos);
pos = moveObject(pos, FORWARD);
printPosition(pos);
pos = moveObject(pos, LEFT);
printPosition(pos);
// invoking moveObject() with one argument
// will move the object forward
pos = moveObject(pos);
printPosition(pos);
function moveObject(position, direction) {
// assume FORWARD if no direction is specified
if (typeof direction === 'undefined') {
direction = FORWARD;
}
if (direction === FORWARD) {
++position.z;
}
if (direction === BACK) {
--position.z;
}
if (direction === LEFT) {
--position.x;
}
if (direction === RIGHT) {
++position.x;
}
return position;
}
function printPosition(pos) {
alert(pos.x + ", " + pos.y + ", " + pos.z);
}
Here's a fiddle that shows a working demo of another approach.
There are two concepts that are at play here.
1 . Variable number of function parameters (or optional parameters).
If you are going to call the same function with different number of parameters (this will eventually lead to a world of headache), you need to determine (inside the function) how this function was called. You can use arguments object available inside each function:
function Too() {
if (arguments.length == 4) {
arguments[0]*arguments[0];
arguments[1]*arguments[1];
arguments[2]*arguments[2];
return ++arguments[3];
} else if (arguments.length == 1) {
return ++arguments[0];
} else {
// you decide what to do here
}
}
2 . Asynchronous code execution.
Realize that Too which is called when interval expires, executes well after One completes and returns. If you want Too to affect newVal variable, and somehow get at this new value afterwards, - make newVal variable global.