Creating an array with copy of object (Javascript) - javascript

I'm trying to write a "universal" array filler that fills an array with a given object. I simulted a class in javascript and now I want to write a function that fills the array with types of that class
function fillArray(theArrayToFill,amount,theObject) {
for ( var i = 0; i != amount; ++i )
{theArrayToFill.push(theObject);}
}
But fillArray (theArray,3,new Enemy(0,0)); fills the array with a reference to that object "enemy" and that's not what I want, I want an exact copy, but when I mutate object 0, object 2 may not change.
Please Help
Thanks

I would recommend you to add a clone method to your object. The clone method should create a new object and set it's value by copying the current object, then the method return this new object.
example:
function clone(obj)
{
var newObj = new YourObject();
newObj.setName(obj.getName());
//Do this for every properties
return newObj;
}

If you are using Underscore, it provides a clone helper function.
function fillArray(theArrayToFill,amount,theObject) {
for ( var i = 0; i != amount; ++i )
{theArrayToFill.push(_.clone(theObject));}
}

Since you already have the constructor, here is how you can use it:
function fillArray(theArrayToFill,amount,ctor) {
for ( var i = 0; i != amount; ++i ) {
theArrayToFill.push(new ctor(0,0));
}
}
// usage:
fillArray(theArray,3,Enemy);
The way you originally called the fillArray method, you created one object (immediately before the function is called) and passed it as parameter to the fillArray method. The method then proceded to fill the array with references towards that object, so each item in the array would indeed point towards the same object.
EDIT:
No simple solution comes to mind if you want to pass different arguments to the constructor. Here is a hacky one that might be enough for your purposes:
function fillArray(theArrayToFill,amount,ctor) {
for ( var i = 0; i != amount; ++i ) {
theArrayToFill.push(new ctor(arguments[3], arguments[4], arguments[5],
arguments[6], arguments[7], arguments[8], arguments[9], arguments[10],
arguments[11], arguments[12], arguments[13], arguments[14]));
}
}
// usage:
fillArray(theArray,3,Enemy,0,0);
fillArray(theArray,3,Friend,1,2,3,4,5,6,7,8);
Obviously this only works for constructors with less than 12 arguments and some checks based on used parameters in a constructor will also fail, but it gets the job done.
PS: I don't suggest you use this approach. Looks like a clone method is more suited to your purpose.

you can use Object.create()
function fillArray(theArrayToFill,amount,theObject) {
for ( var i = 0; i != amount; ++i ) {
theArrayToFill.push(Object.create(theObject));
}
}
or if you want return new array filled default value you can use next code
function fillArray(amount,theObject) {
return Array.apply(null,Array(amount)).map(function(_){return Object.create(theObject);});
}

Related

assigning a new object and keeping the reference?

consider this:
var o = { a: 1 }
read(o);
write(o);
read(o);
function read(x) {
console.log(x);
}
function write(x) {
x = { a: 2 };
}
Obviously the result is:
Object { a=1 }
Object { a=1 }
The write Function destroys the reference to the object by assigning a new object. Is there a way to do both - assigning a new object and keeping the reference? I need this to concat two Float32Arrays. As far as I could find out there is no possibility to concat them without creating a new Float32Array. Or is there one? They are supposed to be fast, but to me it looks rather slow if I always have to create a new one if I want to combine two fragments. But maybe this is another question.
How about this:
function overwrite(x,y){
for (var prop in y) {
if( y.hasOwnProperty(prop) ) {
x[prop] = y[prop];
}
}
}
Example: overwrite(o,{a:2});
(ES6) To insert values from one array into a typeed array, starting at an arbitrary index, try the typed array set() method.
// dest ... destination typed array
// scr ... array like object with elements to add
dest.set(src, dest.length); // append src elements to dest typed array

Javascript: Determine if all of the elements in the array are keys in the object

I am trying to figure out if all of the elements in an array are keys in the object.
var obj = { name: 'Computer', cost: '$1,000' };
var myArray = [ 'name', 'cost', 'bio' ]; //another example would be var myArray = [];
for(var x = 0; x < myArray.length; x++){
if (myArray[x] in obj)
{
return true;
}
}
How can I check if all of the elements in an array are keys in the object?
Do it the other way around. If you find someone in the array who is NOT in the object then you return false. If you reach the end of the loop then you return true because all the keys were in the object.
Depending on what you want, this might do the trick:
function hasKeys(obj, keys) {
for (var i=0; i != keys.length; ++i) {
if (!(keys[i] in obj))
return false;
}
return true;
};
One subtlety you need to ask yourself: do you want to know if the object has the keys directly (i.e. not somewhere in its prototype stack?) If so, then replace keys[i] in obj with obj.hasOwnProperty(keys[i])
function hasKeys(obj, keys) {
return keys.every(Object.prototype.hasOwnProperty.bind(obj));
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every states, "The every method executes the provided callback function once for each element present in the array until it finds one where callback returns a falsy value (a value that becomes false when converted to a Boolean). If such an element is found, the every method immediately returns false. Otherwise, if callback returned a true value for all elements, every will return true. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values" (emphasis mine).
Array.some() makes for a clean solution.
// object in question
var obj = { ... };
// keys that need to be present in the object
var keys = [ ... ];
// iterate through the whitelist until we find a key that doesn't exist in the object. If all exist, that means Array.some() is false.
var valid = !keys.some(function(key) {
return !obj.hasOwnProperty(key);
});
An alternative solution would be using a similar concept, but with Array.every(). It is to note that this will generally be slower because it always has to touch every element in the whitelist.
// iterate through the whitelist, making sure the object has each key.
var valid = keys.every(obj.hasOwnProperty);
This problem can be expressed in terms of set inclusion: does the set of property keys completely include the array of required keys? So we can write it as
includes(Object.keys(obj), arr)
So now we just need to write includes.
function includes(arr1, arr2) {
return arr2.every(function(key) {
return contains(arr1, key);
}
}
For contains, we could use Underscore's _.contains, or just write it ourselves:
function contains(arr, val) {
return arr.indexOf(val) !== -1;
}
If we are interested in conciseness at the possible expense of readability, we could shorten our definition of includes to use Function#bind instead of the anonymous function:
function includes(arr1, arr2) {
return arr2.every(contains.bind(0, arr1));
}
Now we have functions we can use for other things, instead of mixing up the two different aspects of the problem--the keys of an object, and set inclusion. If we really want to write an all-in-one function, it becomes the somewhat more readable:
function hasMany(obj, arr) {
return arr.every(_.contains.bind(0, Object.keys(obj));
}
If we want more readability, like we were writing a novel:
function object_has_required_keys(object, required_keys) {
var object_keys = Object.keys(object);
function key_is_present(key) {
return object_keys.indexOf(key) !== -1;
}
return required_keys.every(key_is_present);
}
Underscore's _.intersection
If we're lazy (or smart), we could use Underscore's _.intersection to implement includes:
function includes(arr1, arr2) {
return _.intersection(arr1, arr2).length === arr2.length;
}
The idea is to take the intersection, and if the first array includes the second entirely, then the intersection will contain all the elements of the second array, which we can check by comparing their lengths.
Using ES6 sets
Thinking ahead to ES6, we could implement include using its sets, which ought to be faster:
function includes(arr1, arr2) {
var set = new Set(arr1);
return arr2.every(Set.prototype.has.bind(set));
}

Javascript function that takes variable number of arguments - changes their value - and then returns them

I am new to Javascript (and programming in general) and have been searching for a way to change the value of an arbitrary number of aguments using a Javascript function.
The answer here (JavaScript variable number of arguments to function) was quite helpful. I was able to use it to create the two of the functions I need, but I'm having trouble with the third.
Basically I would like to pass a variable number of objects (primitive or more complex) into a function and have the function change the value of each object.
var pants = true;
var house = true;
var hair = {/* lots of stuff */};
var onFire = function() {
for (var i = 0; i < arguments.length; i++) {
arguments[i] = false;
}
};
onFire(pants, house, hair);
Console outputs:
>pants;
true
>house;
true
>hair;
Object
How can I formulate this function so the the result is:
>pants;
false
>house;
false
>hair;
false
Any help would be greatly appreciated!
Edit:
To clarify things - I am trying to create a reusable helper function that changes the value of any object passed in to false instead of typing:
var a1 = false;
var a2 = false;
...
var a+n = false;
If I use mathec's method - is it possible to 'parse' object so that it's properties overwrite the global variables of the same name, or am I stuck with typing it out explicitly each time?
var object = {
pants: {/* lots of stuff */},
house: {/* lots of stuff */},
hair: {/* lots of stuff */}
};
function modifyObject(obj) {
obj.pants = false;
obj.house = false;
obj.hair = false;
}
function someMagic(object){
// wand waves...
// rabbit exits hat....
}
Console Output:
>pants;
false
>house;
false
>hair;
false
When you pass variables in JavaScript you're passing a copy of a reference to a value if it's an object, but if it's a primitive (like a true/false) you're copying the actual value. This basically means, if you pass in an object and modify one of the object's properties, you'll be modifying the original object. But if you pass in a primitive like true/false, you'll just be modifying the copy, and not the original value. So if your goal is to modify the original values, one option is to store those values in an object and pass in the object instead. For example:
var object = {
pants: true,
house: true,
hair: {}
};
function modifyObject(obj) {
obj.pants = true;
obj.house = true;
obj.hair = true;
}
If you want to modify an arbitrary number of arguments, just remember that if you're passing in true/false you're copying those values. So if you change them inside the function you won't be modifying the original values.
A quick way to remember this is if you ever pass an object or an array, you're modifying the actual object. Anything else, you're modifying a copy.
Edit
So interpreting what you want to do literally, you could write this:
var a = true,
b = true;
/* pass in variable names */
function makeFalse() {
var i, len;
for (i = 0, len = arguments.length; i < len; ++i) {
window[arguments[i]] = false;
}
}
makeFalse("a", "b");
But I can't think of a good reason to do this :-). I would use configuration objects to store flags and state variables, not global variables.
Unfortunately, this is not directly possible.
Javascript is a pass-by-value language, and in the case of object types, its a pass by value by reference (at least thats how Ive seen it referred to)
Is JavaScript a pass-by-reference or pass-by-value language?
goes pretty in depth to it, and https://stackoverflow.com/a/3638034/1093982 in particular has a great answer.
here is a jsfiddle demonstrating the example in the above answer:
http://jsfiddle.net/hjPHJ/
note how anything assigning to a parameter is not carried into the scope above.
You could try JavaScript's typeof() function, which should return "object", and then treat it differently in your code. As for changing the value of an object, I think you actually want to change the value of a property, but I am not sure I understand your question well enough.
To change an object property, you would do something like this.
hair.color = 'red';
If you want to unset the object, you can do this.
delete window.some_var;
Javascript passes each argument as a reference by value, so when you change the value of a passed in reference it modifies the copied value.
However it does have something else which is very powerful and thats closure. In your example onFire already has access to pants, house, and hair through the closure scope and can modify them directly.
When you call a function in javascript, you are passing values and not references to the original object. There are a couple of ways that you can do what you want, but not directly by passing each value to change to the function.
First you can pass an array:
function onFire(arr) {
for (var i = 0; i < arr.length; i++) {
arr[i] = false;
}
}
arr = [true, true, {}];
onFire(arr); // arr[0] through arr[2] are now false
Another would be to pass an object, whose properties can be modified, you just can't change the value of the variable you pass as an argument:
function onFire(obj) {
obj.pants = false;
obj.house = false;
obj.hair = false;
}
onFire( { pants: true, house: true, hair: { } } );
// obj.pants, obj.house and obj.hair are now false
Neither of these accomplishes just what you want, but if I knew the reason for doing what you are asking there might be a better way...

How String.concat() implements in javascript?

In function .concat(), I can pass an arbitrary number of arguments to it.
I understand function overloading in C++, but I don't know how implement a function with unknown number of arguments in JavaScript.
How do I implement an arbitrary number of arguments to a function?
In javascript, you would use the built in parameter called "arguments" which is an array of all the arguments passed to the function. You can obtain it's length with arguments.length and each value from the array arguments[0], arguments[1], etc... Every function has this built in variable that you can use.
For example, a function to concatenate all strings passed to it.
function concatAll() {
var str;
for (var i = 0 ; i < arguments.length; i++) {
str += arguments[i];
}
return(str);
}
var f = concatAll("abc", "def", "ghi"); // "abcdefghi"
You can do this using the arguments object. See the examples and documentation here: https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments
Like this -
function f()
{
var i;
for(i=0; i<arguments.length; i++)
{
alert( (i+1) + "th argument: " + arguments[i]);
}
}
All the functions in javascript has a built-in parameter called arguments which is an array containing all the function arguments passed to the function. Just iterate over this array and you will be able to access all the arguments of a function.
As an example, once I've written a function which is used to enable/disable certain button if some specific fields were not empty. I wrote this function this way -
function toggleButton() // I used jquery inside this function
{
var i;
var last = arguments.length-1;
for(i=0; i<last; i++)
{
if( $.trim($(arguments[i]).val()) === "" )
return false;
}
$(arguments[last]).toggle();
return true;
}
and called this function like this -
toggleButton("#idOfFirstField", "#idOfSecondField", "#idOfButtonToToggle");
or like this -
toggleButton("#idOfFirstField", "#idOfSecondField", "#idOfThirdField", "#idOfButtonToToggle");
so in both the cases, I was passing variable number of field ids to the function and it checked that if these fields were empty. If all of them contained some value, then it toggled the visibility of the button.
Like this - use the arguments object all functions have available :
function someFunction() {
for (var i=0,n=arguments.length;i<n;i++) {
// do something with arguments[i];
}
}
You can use the arguments array to access parameters that are not formally declared inside the function:
function printArguments() {
for (i = 0; i < printArguments.arguments.length; i++)
document.writeln(printArguments.arguments[i] + '<br />');
}
printArguments(1, 2, 3, 'etc');
Source: http://www.irt.org/articles/js008/
Any javascript function can have an arbitrary number of arguments. If function execution depends on the number or specific qualities of it's arguments, you'll have to check the arguments object, which can be iterated like an 'Arraylike' object, as others have shown.
In some cases it may be handy to convert the arguments to a real array, using something like
var args = Array.prototoype.slice(arguments).
Here's a blog entry from John Resigs page on method overloading that may interest you.

How to implement such an associative array?

arr[key] = value;
where key is a jQuery object and value is an array.
Associative arrays don't really exist in JavaScript. However, you can achieve similar functionality using JavaScript objects:
// Create object
var myObject = {
key: value,
helloText: "Hello World!"
};
// Access object in some statement via:
myObject.helloText
// ...or:
myObject["helloText"]
To use an object as a key, you would have to do something like:
var a = {
helloText: "Hello World!"
};
var b = {};
b[a] = "Testing";
alert(b[a]); // Returns "Testing" (at least, in Safari 4.0.4)
Using an object as a key sounds a bit weird, though. Are you sure you need to do this?
Update:
You can't actually use an object as a key in JavaScript. The reason the above code appears to work is that, in the statement b[a] = "Testing";, JavaScript converts a to a string via a.toString(), which results in "[object Object]", and uses this string as the key. So our statement is actually b["[object Object]"] = "Testing"; and our alert statement is exactly the same as alert(b["[object Object]"]);.
Thanks to CMS for pointing this out in the comments!
Update 2:
Tim Down points out that his JavaScript library jshashtable allows you use an object as a key.
You can use jshashtable, which allows any JavaScript object as a key.
Just guessing here, but it seems you're trying to associate some (arbitrary) data with a jQuery object (possibly an element). In that case, why not use the data () method?
$('#el').data (value);
You can't use objects as keys, and assocative arrays are not what they seem in Javascript because all you're doing is setting a property on the array object, when you loop through by the .length it natively doesn't account for the manually defined properties you set.
I suggest storing the elements and arrays inside of object literals, all inside of an array. Eg:
var list = [
{
el:document.body,
arr:[1,2]
}
];
for ( var i = 0, l = list.length; i<l; ++i ) {
alert( list[i]['el'] )
alert( list[i]['arr'][0] )
}
// add elements to the array
list.push({
el:document.body.firstChild,
arr:[3,4]
})
As kprime mentioned in his answer though, it might be better to use .data() if you are using Javascript.
if ( !$(el).data('key') ) {
$(el).data('key', [2,3,4] );
}
I would suggest assigning a unique ID to each element you want to put in the associative container (object in JS) and use the ID as key:
var idCounter = 0;
var container = { };
function storeValue(element, value) {
if (!element.getAttribute('id')) {
element.setAttribute('id', makeID());
}
var id = element.getAttribute('id');
container[id] = value;
}
function makeID() {
return 'unique-id-' + idCounter++;
}
EDIT: This solution assumes that jQuery is not available. If it is, use data('key', value).
every javascript object is an associative array, this is a property build in the language, you do not need to anything special, just use it like that

Categories

Resources