I have this global variable which contain function names. I am able to execute the function without parameters, but after passing some parameters, I get this error below.
"Uncaught TypeError: undefined is not a function"
//Globally Called and refilled with function names
var function_name = new Array();
//This is the function that executes the var that contains function name
function execute(){
var function_count = function_name.length;
while (function_count--)
{
window[function_name[function_count]](arguments);
}
}
//This is how I add the function with its parameters
function_name.push("GetStatusDetails("+ sampleData +")");
Could you guys guide me with this I am newby in javascripting. Using the function above. Thanks everyone.
You cannot use arguments like this. This results in the arguments pseudo-array being passed as the first parameter. You need to do
window[function_name[function_count]].apply(window, arguments);
However, as mentioned in a comment, you also need to store a pure function name in your function_name array, and pass the arguments to execute, as in
function_name.push("GetStatusDetails");
execute(sampleData);
But why are you passing function names around? Just pass the functions around. So:
function_name.push(GetStatusDetails);
Then you call it directly, instead of pulling it out of the window object by name:
function_name[function_count].apply(window, arguments);
If you want to queue up function+params for later execution, then try something like:
//Array of functions to be called
var function_array = new Array();
//This is the function that executes the functions in the array
function execute(){
var function_count = function_array.length;
while (function_count--)
{
function_array[function_count]();
}
}
//This is how I add the function with its parameters
function_array.push(function() {
GetStatusDetails(sampleData);
});
It would be better programming practice to encapsulate some of this along the following lines:
var FunctionQueue = {
_queue: [],
queue : function(fn) { this._queue.push(fn); },
execute: function() { var fn; while (fn = this._queue.pop()) { fn(); } }
};
FunctionQueue.queue(function() { GetStatusDetails(sampleData); });
FunctionQueue.execute();
function_name.push("GetStatusDetails("+ sampleData +")"});
Here you're not pushing back a function but the result of the function call GetStatusDetails(sampleData). window doesn't contain a key of the signature, so trying to find it with window[...] returns undefined. When you try to call it with window[...](arguments) that's how you got the error, because you can't "call" undefined.
sampleData should be passed into execute() at the call sight and you should be pushing back the name of the function:
function_name.push("GetStatusDetails");
Moreover, arguments is an array of the arguments, not the actual arguments. So GetStatusDetails() will have to go through the array to find the actual argument. Go see #torazaburo's answer that gives the correct solution.
Related
I have a function here, inside that function, there's a helper function. Right now my error is pointing to the first bracket of my display function.
function main() {
// Array of objects
// Sorted those objects
display() { <---Error here
}
}
There's an array of objects where I mapped what I needed and sorted them. After that within that same function, this display function should show up on the DOM, but am getting unexpected token {
What am I missing?
ANSWER
Thanks to everyone, I understand where my confusion was. In some instances, specifically when dealing with classes, I saw that the function keyword was omitted whenever declaring functions within that class.
That is possible due to prototype inheritance I believe and in any other case the function keyword is needed.
It dosen't work since display() is calling (the non-existing) function display. (you can only use that kind of declaration in an object).
Below you see other ways to declare the function:
function main() {
// Array of objects
// Sorted those objects
display() { <---Error here because it is calling a function
}
function display2() {
// this works
}
const display3 = () => {
// this works too.
}
var display4 = function() {
// this wors too, as suggested by Sagar V 2
}
}
update
You can omit the function keyword when defining functions in an object initializer:
const myObject = {
traditionalWay: function() {
},
newWay() {
}
}
Background
I want a function keeping track of its own state:
var myObject = {
myFunction: function () {
var myself = this.myFunction;
var firstTime = Boolean(!myself.lastRetry);
if (firstTime) {
myself.lastRetry = Date.now();
return true;
}
// some more code
}
}
The problem with the above code is that the value of this will depend on the site of the function call. I want the function to be able to refer to itself without using:
myObject.myFunction
.bind()
.apply()
.call()
Question
Is it possible to give a function this kind of self awareness independent of its call site and without any help from external references to it?
If you want to store that state on the function instance, give the function a name, and use that name within it:
var myObject = {
myFunction: function theFunctionName() {
// ^^^^^^^^^^^^^^^--------------------- name
var firstTime = Boolean(!theFunctionName.lastRetry);
// ^--------------------------- using it
if (firstTime) {
theFunctionName.lastRetry = Date.now();
// ^------------------------------------------------ using it
return true;
}
// some more code
}
};
You'd do that whenever you want to use a function recursively as well. When you give a name to a function that way (putting the name after function and before (), that name is in-scope within the function's own code. (It's not in-scope for the code containing the function if it's a function expression, but it is if it's a function declaration. Yours is an expression.)
That's a named function expression (where previously you had an anonymous function expression). You may hear warnings about NFEs, but the issues various JavaScript implementations had with them are essentially in the past. (IE8 still handles them incorrectly, though: More in this post on my blog.)
You might consider keeping that state somewhere private, though, via an IIFE:
var myObject = (function(){
var lastRetry = null;
return {
myFunction: function() {
var firstTime = Boolean(!lastRetry);
if (firstTime) {
lastRetry = Date.now();
return true;
}
// some more code
}
};
})();
Now, nothing outside that outer anonymous function can see lastRetry at all. (And you don't have to worry about IE8, if you're supporting stubborn XP users. :-) )
Side note: The unary ! operator always returns a boolean, so your
var firstTime = Boolean(!theFunctionName.lastRetry);
...is exactly equivalent to:
var firstTime = !theFunctionName.lastRetry;
...but with an extra unnecessary function call. (Not that it hurts anything.)
Of course you can, simply give your function an internal named representation and it can refer to itself from there. For example...
var obj = {
doThings:function doThingsInternal(arg1, arg2) {
console.log(arg1, arg2);
for (var arg in doThingsInternal.arguments) {
console.log(arg);
}
}
};
obj.doThings('John', 'Doe');
You could use a simple Closure, if you are not too bent on keeping state existence knowledge within the function. But I guess you don't want that. Another way to do this could be changing the function itself on the first call. Benefits, no/less state variables needed and no costly checks on subsequent calls! -
var myObject = {
myFunction: function () {
// Whatever you wanna do on the first call...
// ...
// And then...
this.myFunction = function(){
// Change the definition to whatever it should do
// in the subsequent calls.
}
// return the first call value.
}
};
You can extend this model to any states by changing the function definition per your state.
function abc(){
//multiple variables and functions
a:function(){alert("a")};
}
function test(){
var k=abc();
k.a();
}
In the above case, I have a huge function abc() to be assigned to a variable. I want to call the member functions that are visible, like a() from the variable. Is this possible to implement and please give me a sample code if so.
When you include the parenthesis after your function, you're assigning the result of the function to your variable.
If you want to assign the function itself, just omit the parenthesis:
var k = abc;
k.a();
EDIT
Per #Kuba Wyrostek's answer, and #Pointy's comment, that a() function won't be properly exposed.
You'll need to take a look at the Module Pattern. What you need to do is to assign a function to a variable, and have that function return the functions that you want to be able to use outside of that function. This helps with encapsulation.
It's a little hard to tell from your code in the comment exactly what is the user-generated code, but I'll do my best.
var abc = (function () {
var grabApi,
initialize;
// Just an example of how to assign an existing function
// to a property that will be exposed.
grabApi = SCORM2004_GrabAPI();
// This is an example of how to have a property that will be
// exposed be a custom function passing a parameter.
initialize = function(initString) {
return SCORM2004_GrabAPI().Initialize(initString);
};
return {
getApi: grabApi,
init: initialize
}
}());
You can then use this abc object like this throughout your code. Again, this is trying to give an example of how to do what I think you're trying to do based on your comment.
// Assign the SCORM2004_GrabAPI function to a variable.
var SCORM2004_objAPI = abc.getApi();
// Call the Initialize function with an empty string.
abc.init("");
Hmmm… contrary to #krillgar's answer, I believe you were expecting your abc() to return new object. Something like this:
function abc(){
var privateVar;
return {
//multiple variables and functions
a:function(){alert("a")}
}
}
function test(){
var k=abc();
k.a();
}
You should make it an object. In this way you can access its property a.
var abc ={
a:function(){alert("a")}
}
function test(){
var k=abc;//Ofcrse remove the parenthesis
k.a();
}
test();
I've done some leg work on getting this code to behave the way I want it to up to a certain point.
However I have encountered problem that requires a little bit of direction in helping me to solve the issue.
Problem to solve
Comments in code will explain what I am trying to archive..
var myArr = ["Brent white","brentw.white"];
function nameFoo (name){
var strSplit = name.split(" "); // splitting Brent White
var nameStr = this. myArr; // fetching Brent white string from myArr
console.log (strSplit,myArr[0]);
}
nameFoo("Brent White"); // calling nameFoo function
var myData = {
someData:"somedata",
someMoreData:"moredata",
myName:function(){
// I need to call nameFoo function through myName method.
// My hypothesis is that return will use the (this) keyword within the object?
}
};
// Here I need to call the method to have access my nameFoo? Correct me if I am wrong?
// Is this method invocation?
// Please help..Lost here...
To sum it up, I want myName method to call the nameFoo function. nameFoo will then give me myName method the result.
If someone could be kind enough to demonstrate how to get through this last step then I would be very grateful.
Pointing me in the right direction would also be greatly appreciated..
PS I am new to JS.
Be careful with the 'this' keyword. By calling nameFoo in a global context ie:
// some code
nameFoo(arg);
// some more code
'this' will always refer to 'window'. So, when you call myData.myName, even though this object calls the nameFoo method, 'window' will still be referenced in nameFoo's 'this'. 'this' is normally scoped to the object the function belongs to.
If you need 'this' to refer to one of your custom objects, use the Function prototype method "call" from within your myName function.
var myData = {
...
...
myName: function() {
nameFoo.call(this, someArgument);
};
Note that someArgument will be the argument passed to 'nameFoo' -- which will throw an error if you do not supply an argument. It's up to you to figure out what you want to pass.
More info about Function.prototype.call:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
More info about Function.prototype.apply:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
The only real difference between the two is how you supply arguments to the function you are calling. With "call", you separate the arguments with commas (as you would when normally executing a function).
eg: nameFoo.apply(this, arg1, arg2, arg3);
With "apply", you supply the arguments as an array.
eg: nameFoo.apply(this, [arg1, arg2, arg3]);
I'm thinking this conceptually may help you out:
// Some names in array
var my_names = ["Brent White", "John Smith"];
// Returns name array [First, Last]
function nameParse(full_name) {
return full_name.split(" ");
}
// Person object (properties)
function Person(name) {
this.full_name = name;
this.name_array = nameParse(name);
this.first_name = this.name_array[0];
this.last_name = this.name_array[1];
}
// Create single person example
var brent = new Person(my_names[0]);
// Access properties of brent
console.log(brent);
console.log("Hey, my first name is " + brent.first_name);
// Alternate example --------- //
// Store our people here
var my_people = [];
// Create a person for each name
for (var i = 0, max = my_names.length; i < max; i += 1) {
var some_person = new Person(my_names[i]);
my_people.push(some_person);
}
console.log(my_people);
if (!window.statistics) window.statistics = {};
statistics.Update = function (var sales) {
...
}
Here I get the error Unexpected token var on the var sales argument. I expect something like this is because I cannot pass any arguments to this type of function. If I have the same function type without arguments it works.
Why is this and how do I pass a value to this function?
Just remove the var, and your function will have one named argument. When you call it (you're never calling it in your code), you'd pass in whatever value you want it to receive in that named argument.
if (!window.statistics) window.statistics = {};
statistics.Update = function (sales) {
// No 'var' here -------------^
console.log(sales);
}; // <== Off-topic: Note the semicolon
statistics.Update("foo"); // Logs "foo" to the console
You only have to give your parameters a name, you do not specify a value.
statistics.Update = function (sales) {
...
}
You can pass your value by calling the method like this:
var s = '';
statistics.Update(s);