JavaScript object as parameter - javascript

I tried to make a function that writes some divs in an HTML document. Everything is working fine but I want to try to change the function declaration from this:
function writeDiv(divDOMelement, numberOfExcercises, numberOfTasksInEx);
To something like this
function writeDiv(divDOMelement, {numberOfExcercises:N, numberOfTasksInEx:[v]})
Just to be clear, the first declaration works perfectly, but when I tried implementing the second one, and changing the function call I received an error.
Here is the full code:
let open = false;
let currentlyOpen;
function writeDiv(divDOMelement, {numberOfExcercises:N, numberOfTasksInEx:[v]}) {
for (let i = 0; i < numberOfExcercises.N; i++) {
// ... didnt include the code that prints the divs on the site just to make it easier to read.
for (let j = 0; j < numberOfTasksInEx.v[i]; j++) {
// ... same as the first loop.
}
}
}
$(document).ready(function () {
writeDiv("#mainDiv", {numberOfExcercises:3, numberOfTasksInEx:[5,2,3]});
});
Just to clarify, this numberOfTasksInEx should be an array, the first element of the array tells me that the first exercise will have that many tasks, the second tells me that the second exercise will have that many tasks, and so on.
The error I am getting:
jQuery.Deferred exception: numberOfExcercises is not defined
Uncaught ReferenceError: numberOfExcercises is not defined

Your declaration syntax is incorrect. All you need is:
function writeDiv(divDOMelement, {numberOfExcercises, numberOfTasksInEx})
Then inside your function you'll have numberOfExercises as the overall count, and numberOfTasksInEx as the array of per-exercise tasks.
The declaration syntax extracts those properties from the single object passed in as the second parameter to the function in a process called "decomposition". The : in your version does something, but not what your code expects: it allows the property name from the source object (the actual parameter) to be renamed. That's not really necessary here, but for example numberOfExercises:N would mean that in your function you would refer to simply N, not numberOfExercises.N.

Related

Do I have to use the same prepareCall when using addBatch & executeBatch? Why?

I'm new to using JDBC and am learning how to use batch processing. After wasting a lot of time trying to figure out why my combination of JavaScript and SQL stored procs didn't work, I think I learned that you have to use one prepareCall when using addBatch and executeBatch. Is this true? If so, why?
To exemplify, here's some example input:
var vals = [["value1_1","value2_1","value3","value4","value5","value6_1"],
["value1_2","value2_2","value3","value4","value5","value6_2"]]
The below loop works as expected. Note that I prepareCall before entering the loop.
params = Array(vals.length).fill("?")
pstmt = conn.prepareCall("{call "+storedProcedure+"("+params+")}");
for (var i = 0; i < vals.length; i++) { // for each array
for (var j = 0; j < vals[i].length; j++) { // for each value within each array
// set the string
pstmt.setString(j+1, vals[i][j]);
}
pstmt.addBatch();
}
try {
pstmt.executeBatch();
} catch (err) {
//my err msg code
pstmt.close();
conn.close();
}
Now, sometimes I have records that have a different number of parameters so I thought that I could just move prepareCall into the first loop so that I can change the number of parameters as needed for each input array.
for (var i = 0; i < vals.length; i++) { // for each array
// moved prepareCall here
params = Array(vals.length).fill("?")
pstmt = conn.prepareCall("{call "+storedProcedure+"("+params+")}");
for (var j = 0; j < vals[i].length; j++) { // for each value within each array
// set the string
pstmt.setString(j+1, vals[i][j]);
}
pstmt.addBatch();
}
try {
pstmt.executeBatch();
} catch (err) {
//my err msg code
pstmt.close();
conn.close();
}
For this second loop, I don't get any errors from Javascript but I get a foreign constraint error from my stored proc. My stored proc makes a set of CALLs to create records based on the value of the last parameter. I understand that the error that I get is telling me that one of the FKs doesn't exist. This would only happen if the wrong set of CALLs was invoked or the right set of CALLs was invoked but one of the CALLs failed. I'm sure neither is the issue since the first loop works as expected.
Thus, I'm interested to learn why I have to use one prepareCall when I executeBatch? To confirm, I have to use totally separate prepareCalls when I have call different stored procedures with different numbers of parameters?
I don't think it matters but for good measure: I'm using MySQL 5.7.
The method prepareCall returns a CallableStatement object that is compiled for the specific statement that you passed to prepareCall. When you call addBatch, the set of parameters is added to that specific instance of CallableStatement. If you execute prepareCall again, you get a different CallableStatement handle, with its own batch.
So, in your second piece of code in each iteration of the outer loop, you create a new CallableStatement, losing the previous callable statement and its batch (creating a memory leak as well in your code and possibly in your DBMS). As a result, when you call executeBatch, you will only execute the last statement you prepared, with only a single set of parameter values.
If you need to execute distinct statement texts, you will need to prepare and execute them in order, and you cannot use batch(*).
* - You could use batch if multiple sets of parameters use the same statement text, but if there are order dependencies between different statement texts, this might get tricky

Calling a custom method on the Array prototype in Nodejs

I'm trying to add a custom method on the prototype of the Array object:
Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
}
But, I'm receiving the error below when I'm calling the method like this:
[1,2,3].demo()
// Error: TypeError: Cannot read property 'demo' of undefined
However, it runs successfully when I change it to:
const arr = [1,2,3];
arr.demo()
// Output: 1, 2, 3
PS. This is in nodejs
To reproduce the error in the browser, copy/paste the full block at once and click enter.
UPDATE: It sounds like we need to add a semicolon to make it work:
Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
}; <=== added semicolon here to work #jfriend00
[1,2,3].demo();
However, now this next code works WITHOUT semicolon!!
String.prototype.demo = function(){
this.split('').forEach(c=>console.log(c))
}
'hello'.demo();
Quick Fix - Add Semi-colon
Add a semi-colon at the end of your function definition:
Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
}; // <======
[1,2,3].demo();
And, it will work.
What's Happening?
The problem is that the [1,2,3] is being combined with the previous function (whitespace between them collapsed). In that circumstance, the [1,2,3] becomes just [3] and tries to read the [3] property from the function object. If you put the semi-colon at the end of the function definition, then that signals the end of the function definition statement and the [1,2,3] can then be interpreted as a static array definition.
It's all about context. In some circumstances in Javascript, [x] is a property access. In other circumstances, it's a static array definition. Without the semi-colon, it was getting interpreted as the property access instead of the array definition.
Remember that functions are objects in Javascript so they can have properties and can respond to [x] as a property access on them.
So, without the semi-colon at the end of the function you essentially have this:
Array.prototype.demo = function() {...}[3].demo();
Because the whitespace is collapsed between the end of your function and the [1,2,3]. That means the JS interpreter is expecting the [] to be a property name so it evaluates the statement inside the [] and in that context [1,2,3] turns into [3] (the 1,2,3 is evaluated which takes the value of the last comma separated statement which is 3).
More Detailed Explanation
Think of it like this:
// defines function
let f = function() {};
// attempts to read a property from that function object
let o = f [1,2,3]; // this is the same as let o = f[3]
// tries to call `.demo()` on the value read from that property
// which was undefined so this throws
o.demo();
Functions Are Objects
As a demonstration of how functions are objects, see this example that actually works!
// defines function
let f = function() {};
f[3] = {demo: function() { console.log("demo!!!");}}
// attempts to read a property from that function object
let o = f[1,2,3]; // this is the same as let o = f[3]
// tries to call `.demo()` on the value read from that property
// which was undefined so this throws
o.demo();
Here, we actually put a property on the [3] property of the function so when f[1,2,3] reads that property, it actually gets an object with a .demo() method on it so when we then call it, it all works. I'm not suggesting one would ever code this way, but I am trying to illustrate how f[1,2,3] is just reading the [3] property from the function object.
Good Reason Not to Leave out the Semi-colons
These odd cases are a good reason not to leave out semi-colons, even though you usually (but not always) get away with it.
The reason is that functions are objects, so if we don't add a semicolon, JavaScript will try to access a property on the function object, after it evaluates the comma operator like this:
function() { ... }[1,2,3].demo();
function() { ... }[3].demo();
undefined.demo();

Function Values and How Are They Executed (How They Work)?

I'm going through Eloquent JavaScript book and am on chapter 5 (Higher-Order Functions) currently. I'm doing good so far and have understood material clearly, but I've come to realize that I don't understand what function values are exactly and how they work. I do understand what functions are and am quite comfortable with the syntax of creating them using the function keyword as you would do in C for example.
Assume the following code from the book:
function forEach(array, action) {
for (var i = 0; i < array.length; i++)
action(array[i]);
}
var numbers = [1, 2, 3, 4, 5],
sum = 0;
forEach(numbers, function(number) {
sum += number;
});
console.log(sum);
How does the forEach function, when called, determine what is the number? How does it extract number from the numbers array. I do understand that action argument in the definition of forEach function "hooks" the action to the element which is currently pointed by the for loop, but I interpret the code as follows:
function(number) {sum += number;}action(array[i])
which doesn't make much sense.
If you could shed light on this issue I'd be more than thankful and also explain what the function value is exactly? How does it differ from function and/or function return value?
Thank you.
From what I've understood, I think that you are being confused by the JavaScript callback function.
In javascript, a function like this:
Look at your code:
function forEach(array, action) {
for (var i = 0; i < array.length; i++)
action(array[i]);
}
forEach(numbers, function(number) {
...
For each item of the array (first argument, accessed via array[i]) you are calling action with that value, action(array[i]).
In forEach(numbers, function(number) {, you have passed action (the second argument) as a function with one input. This is the function being called by forEach with each array element. With each pass of the for loop within forEach, this function is called with the new value.
I think trying this with other examples (just start your js console now and begin messing around) will help you to learn this concept.
If I made a function
function run(callback){
callback();
}
and called it like so:
run(function(){
console.log('foo bar baz');
});
I'd expect to see "foo bar baz" printed to the console.
If I now make a new function, and call it,
function withTheAnswer(callback){
callback(42);
}
withTheAnswer(function(theAnswer){
alert('The answer is ' + theAnswer);
});
I'd expect 42 to be alerted.
Honestly, as you start to learn more about JS, you'll see this used a lot, and therefore fully understand it.
I don't understand what function values are exactly and how they work
A function (in JavaScript) is an object that can be called. A function call is nothing special, it is just any expression (like a variable evaluation) followed by a pair of parenthesis with arguments in between.
You could write
var addToSum = function(number) {
sum += number;
};
forEach(numbers, addToSum);
or
function addToSum(number) {
sum += number;
}
forEach(numbers, addToSum);
and it means basically the same: You have a function object, a variable addToSum that refers to it, and it is passed to the forEach call.
How does the forEach function, when called, determine what is the number?
It doesn't know anything about the numbers. All the forEach function sees are an array value (referred to by the parameter name array) and a function value (referred to by the parameter name action). Then it loops over that array, and calls the action function with each of the elements. Only inside the called function this array element is know as number.
I interpret the code as follows: function(number) {sum += number;}action(array[i]) which doesn't make much sense.
If you expand the variable to its value, the variable name disappears:
(function(number) {sum += number;})(array[i]);
which does actually make sense - as I've written above, a function call is just an expression followed by parenthesis. And that expression needs to evaluate to a callable object, which this function expression does.
You might also rewrite it as
function action(number) { sum += number; }
action(array[i]);
if that make more sense to you.
action attribute is a function. This function doesn`t called until you put: 'action([a number])'. Then inside the for loop for each element of array attribute is called the function action with corresponding number.
As #theonlygusti says this function are called callbacks.

JavaScript Prototype: An Interesting Object has no method Error

I'm making an HTML5 game and thinking 15 levels for it. I have an levels class that include level objects. This is the code part of it.
function levels(){
this.allLevels=[];
for (var i = 1; i <=15; i++) {
this.allLevels[this.allLevels.length]=new level(); //LEVEL OBJECTS CREATED INTO OBJECT
this.allLevels[this.allLevels.length-1].levelNumber=i; //LEVEL NUMBERS ARE SET
(i==1)? this.allLevels[this.allLevels.length-1].state='ZERO':this.allLevels[this.allLevels.length-1].state='LOCKED'; //LEVEL STATES ARE SET
}
}
As you might see, I have an allLevels array to keep the level information. So far so good everything works. After creating this class I added init and draw methods to this class. Here it is;
levels.prototype.initAll = function(){
for(var i=0;i<=15;i++){
this.allLevels[i].initAllCoor();
}
};
levels.prototype.draw=function(){
this.cleanCanvas();
for(var i=0;i<=15;i++){
this.allLevels[i].drawLevelIcon();
}
};
levels.prototype.cleanCanvas=function(){
ctxCanvasLevels.clearRect(0,0,800,570);
};
It has just three methods for now. The functions you see(initAllCoor and drawLevelIcon) are the level object's methods. When I called these methods, everything works.
You can say if everything works what are you asking. Although everything works smoothly, I'm getting error at the Chrome's console.
Uncaught TypeError: Cannot call method 'initAllCoor' of undefined
Uncaught TypeError: Cannot call method 'drawLevelIcon' of undefined
I can't understand, it says 'cannot call' but it does. Because of this errors I can't use console.log function, too.
When you create the levels:
for (var i = 1; i <=15; i++) {
In the "initAll" function:
for(var i=0;i<=15;i++){
There is never a level 0, yet the "initAll" function expects one.
It's not invalid or wrong, but it's somewhat weird to start filling a JavaScript array at position 1 instead of 0.

getting the name of a variable through an anonymous function

Is it possible to find the name of an anonymous function?
e.g. trying to find a way to alert either anonyFu or findMe in this code http://jsfiddle.net/L5F5N/1/
function namedFu(){
alert(arguments.callee);
alert(arguments.callee.name);
alert(arguments.callee.caller);
alert(arguments.caller);
alert(arguments.name);
}
var anonyFu = function() {
alert(arguments.callee);
alert(arguments.callee.name);
alert(arguments.callee.caller);
alert(arguments.caller);
alert(arguments.name);
}
var findMe= function(){
namedFu();
anonyFu();
}
findMe();
This is for some internal testing, so it doesn't need to be cross-browser. In fact, I'd be happy even if I had to install a plugin.
You can identify any property of a function from inside it, programmatically, even an unnamed anonymous function, by using arguments.callee. So you can identify the function with this simple trick:
Whenever you're making a function, assign it some property that you can use to identify it later.
For example, always make a property called id:
var fubar = function() {
this.id = "fubar";
//the stuff the function normally does, here
console.log(arguments.callee.id);
}
arguments.callee is the function, itself, so any property of that function can be accessed like id above, even one you assign yourself.
Callee is officially deprecated, but still works in almost all browsers, and there are certain circumstances in which there is still no substitute. You just can't use it in "strict mode".
You can alternatively, of course, name the anonymous function, like:
var fubar = function foobar() {
//the stuff the function normally does, here
console.log(arguments.callee.name);
}
But that's less elegant, obviously, since you can't (in this case) name it fubar in both spots; I had to make the actual name foobar.
If all of your functions have comments describing them, you can even grab that, like this:
var fubar = function() {
/*
fubar is effed up beyond all recognition
this returns some value or other that is described here
*/
//the stuff the function normally does, here
console.log(arguments.callee.toString().substr(0, 128);
}
Note that you can also use argument.callee.caller to access the function that called the current function. This lets you access the name (or properties, like id or the comment in the text) of the function from outside of it.
The reason you would do this is that you want to find out what called the function in question. This is a likely reason for you to be wanting to find this info programmatically, in the first place.
So if one of the fubar() examples above called this following function:
var kludge = function() {
console.log(arguments.callee.caller.id); // return "fubar" with the first version above
console.log(arguments.callee.caller.name); // return "foobar" in the second version above
console.log(arguments.callee.caller.toString().substr(0, 128);
/* that last one would return the first 128 characters in the third example,
which would happen to include the name in the comment.
Obviously, this is to be used only in a desperate case,
as it doesn't give you a concise value you can count on using)
*/
}
Doubt it's possible the way you've got it. For starters, if you added a line
var referenceFu = anonyFu;
which of those names would you expect to be able to log? They're both just references.
However – assuming you have the ability to change the code – this is valid javascript:
var anonyFu = function notActuallyAnonymous() {
console.log(arguments.callee.name);
}
which would log "notActuallyAnonymous". So you could just add names to all the anonymous functions you're interested in checking, without breaking your code.
Not sure that's helpful, but it's all I got.
I will add that if you know in which object that function is then you can add code - to that object or generally to objects prototype - that will get a key name basing on value.
Object.prototype.getKeyByValue = function( value ) {
for( var prop in this ) {
if( this.hasOwnProperty( prop ) ) {
if( this[ prop ] === value )
return prop;
}
}
}
And then you can use
THAT.getKeyByValue(arguments.callee.caller);
Used this approach once for debugging with performance testing involved in project where most of functions are in one object.
Didn't want to name all functions nor double names in code by any other mean, needed to calculate time of each function running - so did this plus pushing times on stack on function start and popping on end.
Why? To add very little code to each function and same for each of them to make measurements and calls list on console. It's temporary ofc.
THAT._TT = [];
THAT._TS = function () {
THAT._TT.push(performance.now());
}
THAT._TE = function () {
var tt = performance.now() - THAT._TT.pop();
var txt = THAT.getKeyByValue(arguments.callee.caller);
console.log('['+tt+'] -> '+txt);
};
THAT.some_function = function (x,y,z) {
THAT._TS();
// ... normal function job
THAT._TE();
}
THAT.some_other_function = function (a,b,c) {
THAT._TS();
// ... normal function job
THAT._TE();
}
Not very useful but maybe it will help someone with similar problem in similar circumstances.
arguments.callee it's deprecated, as MDN states:
You should avoid using arguments.callee() and just give every function
(expression) a name.
In other words:
[1,2,3].forEach(function foo() {
// you can call `foo` here for recursion
})
If what you want is to have a name for an anonymous function assigned to a variable, let's say you're debugging your code and you want to track the name of this function, then you can just name it twice, this is a common pattern:
var foo = function foo() { ... }
Except the evaling case specified in the MDN docs, I can't think of any other case where you'd want to use arguments.callee.
No. By definition, an anonymous function has no name. Yet, if you wanted to ask for function expressions: Yes, you can name them.
And no, it is not possible to get the name of a variable (which references the function) during runtime.

Categories