On (document).ready im would like to dynamically generate elements inside a certain parent-element. Lets call them "Candles".
Each "Candle" needs different properties for backgroundImage and color depending on their index().
After creating the page, these attributes need to be changeable via the interface. So its important to save the properties of the "candles" independent from each other.
Thats why I thought it might be useful, to generate for an object for each "Candle" to save their individual properties and to make them editable.
var candleAmount = 3;
for (var i=1; i <= candleAmount; i++) {
$("#container #candles").append("<li><img src=''></img></li>");
var Candle+i = [ "background":"+i+", "color":" - random - (ignore)" ]
};
(please dont mind any failures in the code besides the "Candle+i", I'll figure it out.)
EDIT: Ok, thank you so far. I might not made myself clear enaugh.
Here is an way more reduced example:
$("ul#candles li").each( function(i) {
candle+i = i+" Anything";
});
alert(candle4);
I would love to create an amount of variables depending on the Amount of child-objects.
What would be the correct syntax, or isn't there any?
Thank you
just put them in an array and access them via index. Result is most likely the same for you and is much better than let them floating in your scope
So is there any way, to generate object-names with an index?
Yes, in JavaScript, global variables are defined as properties of the global-object. (Inside a function, variables are defined as properties of the Activation object.) You can reference the global object by window (for browser applications) or just by this.
And because all objects are associative you can give there properties just the name you want. So, setting a global variable is equal to set a property into the global object.
var foo = "bar"; === this["foo"] = "bar";
Now, its just a small step to add a dynamic part to the name:
for(var i=0;i<10;i++) {
this['candle' + i] = i;
}
alert(candle7);
For your specific code:
$("ul#candles li").each( function(i) {
window["candle" + i] = i+" Anything";
});
alert(candle4);
Related
Today while working with some JS I had a bug in my code. I was able to resolve it but I don't really understand why the change I made works. All I can guess is that it comes down to either closure or variable scope.
I was trying to build up a nested hash of arrays like so:
var maxNumberOfPairs = 2;
var container = {};
var pairsHash = {};
$.each(["nurse", "doctor", "janitor", "chef", "surgeon"], function(index, role) {
for(var i = 0; i < maxNumberOfPairs; i++){
var pairIdSubString = "attribute_" + i + "_" + role;
pairsHash["attribute_" + i] = [pairIdSubString + "_night", pairIdSubString + "_day"];
}
container [role] = pairsHash;
});
If you run this you get a nice nested output inside container but when you look at each array in the hash you get a weird behaviour with the string produced.
Each one has the last role in each string like so:
"attribute_0_surgeon_night"
If you log out the variable pairIdSubString it correctly has the role in the string, but as soon as this is added to pairHash it just uses the last element in the $.each array.
I was able to fix it by moving pairsHash inside the $.each but outside the for loop.
Can anyone explain to my why the output was different after moving it inside the each?
Thanks
It actually has to do with reference vs value. When its outside the each you are operating on the same object over and over so every time you set it to the container you are just setting a reference to the same object that is constantly changing. So every reference in container after the loop is the last state of the pairsHash because they all point to the same object.
When you put the pairsHash in the each it is reinitialized every time so they all point to different memory addresses. Not the same one since a new one is created every loop.
To further clarify all objects are just references to a memory address In JavaScript so in order to get new one you need to initialize or to pass by value to a function clone it.
Ok, because my initial question sounds unclear, so I decided to edit it. My question is how do you find out who defined a certain property, for example, the parseInt function, how do I know on which object it was definded like if parseInt was definded on the window object or the document object or whatever object it is? Thank you
I know the parseInt was definded the window object, I am just using it as an example in general, I am not specifically asking what object definded the parseInt property.
Also, please don't show me jQuery codes since I don't know jQuery that very good.
There is unfortunately no way to determine using code what the variable environment is of a given variable.
As for object properties, they should be obvious if they are myObj.property. If not obvious, it could be possible to use an exhaustive search to look for their existence in certain places, or certain known recursively.
Overall, it is not possible to know without looking at implementation documentation.
I know that to solve my question, we could use Object.prototype.hasOwnProperty(), but that would be very alot of typing because you have to type it out each time you need to know if a certain property is defined on a object. I have decided to write my own function to make this a little easier even though this is of no good practical use, I just wanted to satisfy my curiosity.
function findOwner(property, ownerObjectArray) {
var result = []; // Array to store the objects that the given property is defined on
for (var i = 1; i < arguments.length; i++)
{
var obj = arguments[i]; // the object currently being inspected
var properyList= Object.getOwnPropertyNames(arguments[i]); // a list of all "Owned" properties by this object
for (var j = 0; j < properyList.length; j++)
{
if (property === properyList[j]) result.push(obj.constructor);
}
}
return result.length > 0 ? result : "undefinded";
}
run this method
window.onload = run;
function run()
{
alert(findOwner("parseInt", Array.prototype, window, document)); // passing 3 objects we want to test against to this method. It printed : [object Window], the given property "parseInt" was found on the "Window" object
}
I have one module called functionalUtilities which contains a number of utility functions. An abbreviated version looks something like this:
MYAPP.functionalUtilities = (function() {
function map(func, array) {
var len = array.length;
var result = new Array(len);
for (var i = 0; i < len; i++)
result[i] = func(array[i]);
return result;
}
return {
map:map,
};
})();
I then have a second module which contains core code:
MYAPP.main = (function() {
//Dependencies
var f = MYAPP.functiionalUtilities;
//Do stuff using dependencies
f.map(...)
})()
It seems messy and annoying having to remember to type f.map each time I want to use map. Of course, in the dependencies, I could go though each of my functionalUtilities typing:
var map = f.map,
forEach = f.forEach,
etc.
but I wondered whether there is a better way of doing this? A lot of articles on namespacing that I've read mention aliasing, but don't suggest a way to sort of 'import all of the contents of an object into scope'.
Thanks very much for any help,
Robin
[edit] Just to clarify, I would like to use my functional utilities (map etc) within MYAPP.main without having to preface them every time with f.
This is possible by going through each function in MYAPP.functionalUtilities and assigning to a locally scoped variable within MYAPP.main. But the amount of code this requires doesn't justify the benefit, and it's not a general solution.
As I said in the comment. There is no real way of automatically defining local variables out of object properties. The only thing that comes to my mind is using eval:
for (var i in MYAPP.functiionalUtilities) {
eval("var " + i + " = MYAPP.functiionalUtilities[i];");
}
But I wouldn't use this method, since you could have object properties with strings as keys like this:
var obj = {
"my prop": 1
};
"my prop" might be a valid key for an object property but it's not a valid identifier. So I suggest to just write f.prop or define your local variables manually with var prop = f.prop;
EDIT
As Felix Kling mentioned in the comment section, there is in fact another way of achieving this, using the with statement, which I don't really know much about except for that it is deprectated.
Here's a late answer - I feel like adding to basilikum's answer.
1) The with keyword could be useful here!
with(MYAPP.functiionalUtilities) {
map(console.log, [ 'this', 'sorta', 'works', 'quite', 'nicely!' ]);
// Directly reference any properties within MYAPP.functiionalUtilities here!!
};
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with
The with keyword is, in some ways, intended for exactly this situation. It should, of course, be noted that the mozilla developer link discourages use of with, and with is also forbidden in strict mode. Another issue is that the with statement causes its parameter to become the head of the scope chain, which means that it will always be checked first for all identifiers for all statements within the with block. This could be a performance hit.
2) An improvement to basilikum's answer
While a function call cannot add items to its parent-frame's scope, there is a way to avoid typing out a for-loop each time you wish to add a list of items to a namespace.
// First, define a multi-use function we can use each time
// This function returns a string that can be eval'd to import all properties.
var import = function(module) {
var statements = [];
for (var k in module) statements.push('var ' + i + ' = module["' + i + '"]');
return statements.join(';');
};
// Now, each time a module needs to be imported, just eval the result of import
eval(import(MYAPP.functiionalUtilities));
map(console.log, [ 'this', 'works!' ]);
The idea here is to replace the need to write a for-loop with something like eval(import(MYAPP.functiionalUtilities));.
The danger here, as basilikum has stated, is that module properties need to be valid identifier names.
can someone tell me if this is valid javascript? I know you couldnt do this sort of thing in c# but js is a much looser language..
var arrayToUse = "arr" + sender.value;
for (i = 0; i <= arrayToUse.length; i++) {
// something..
}
specifically - the dynamic generation of the array name..
update..
so i have an array called arrMyArray which is initialised on document ready. sender.value = "MyArray" - but could be something else eg MyArray2
I want to dyanimcally iterate over the array that is indicated by the sender.value value.
Yes, this is entirely valid.
arrayToUse will be a string (regardless of the value of sender.value — it will be converted to a string), and i will iterate from 0 to the string's length).
One minor note: it should be for (**var** i = 0; …), otherwise i will be treated as a global variable, which will almost certainly end badly if you've got multiple loops running at the same time.
Edit: you want to get the array based on the name? In that case you've got to look it up in whatever context the array is defined.
If it's a global array, use window.
For example:
var arrayName = "arr" + sender.value;
var array = window[arrayName];
…
To get a variable name defined by a variable, you need to use eval, like so:
var arrayToUse = eval("arr" + sender.value);
However, you must be very careful with this, because controlling sender.value would allow someone to hijack your entire application this way. You should usually try to find another solution.
If the variable is defined at the globally, you can look it up as window["arr" + sender.value] instead. This is still not ideal, but is less of a security risk.
What you need to do is access a variable with the name "arr" + sender.value. Accessing the variable whose contents are "arr + sender.value doesn't do what you want -- that's just a string.
To access the variable with that name, you can look it up as a global (globals are members of the window object in the browser):
window["arr" + sender.value]
This is safer and faster than using eval() because it doesn't run code in a JavaScript execution context to evaluate the string -- it just looks up a variable in the window object with that name.
Is there a way for javascript to detect all assigned variables? For example, if one js file creates a bunch of vars (globally scoped), can a subsequent file get all the vars without knowing what they're named and which might exist?
Thanks in advance :)
EDIT, Question Part 2:
How do I get the values of these variables? Here is what I have attempted:
This is what I ended up with, as per comment suggestions:
for (var name in this) {
variables[name] = name;
variables[name]=this[name]
}
Flanagan's "JavaScript - The Definitive Guide" gives the following on page 653:
var variables = ""
for (var name in this)
variables += name + "\n";
For Firefox, you can see the DOM tab -- easy, though not an answer to your question.
The for in loop provided in Kinopiko's answer will work, but not in IE. More is explained in the article linked below.
For IE, use the RuntimeObject.
if(this.RuntimeObject){
void function() {
var ro = RuntimeObject(),
results = [],
prop;
for(prop in ro) {
results.push(prop);
}
alert("leaked:\n" + results.join("\n"));
}();
}
See also:
Detecting Global Pollution with the JScript RuntimeObject (DHTML Kitchen article)
RuntimeObject (MSDN docs)
There is the this variable. This is an object or an array, and you can simply put:
for(i in this) { //do something }
Unfortunately, it will return everything under the this object.
This will output all the variables into the console without needing to read the variable yourself.
var variables = ""
for (var name in this)
variables += name + "\n";
console.log(variables)
/*
This could work too... but it's such a big unecessary code for something you could do in one line
var split = variables.split("\n");
for (var i in split)
console.log(split[i])
*/
If you want to assign values from one object to another, there are a couple of ways to do this:
//Way 1st
const variables= { ...this };
// or (I don't know what's the difference ;) )
// Don't forget const variables= {};
Object.assign(variables, this);
// Yes. It's very easy. You just "copy" entries from this to variables. I want to note that you are not copying a link to this, namely ENTRY.
Or
// Way 2nd. If u need to do smth. with entries.
const variables= [];
for (const name of Object.keys(this)) {
/*
Doing smth........
*/
variables[name] = this[name];
}
I want to note that this is not a way to collect all declared variables into an object (I am looking for this method myself). They are simply ways of copying the contents of one object into another.