clear and undo clear the array - javascript

If I do have the following code then empty the arry:
var a1 = [1,2,3];
a1 = [];
//returns []
But I'm trying to make a function to clear and undo clear the array, it's not working as expected:
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a;
a = [];
}
function undoClearArray(a){
a = storeArray;
}
clearArray(foo);
foo; //still returns ['f','o','o']
//but expected result is: []

Here's the problem:
You assign an array to a variable foo.
Then you pass this object to your function which stores it in another variable a. Now you have one object that two variable are pointing at. In the function you then reassign a to a different object an empty array []. Now a points at the empty object and foo still points at the original object. You didn't change foo by reassigning a.
Here's a concise way to store you're array:
var storeArray = [];
function clearArray(a){
while (a.length>0){
storeArray.push(a.shift()) //now a is empty and storeArray has a copy
}
}

I tried something different. Maybe it's dirty, but the storage itself is on the object.
the fiddle
//define the object to hold the old data
Object.defineProperty(Array.prototype, "storage", {
enumerable: false,
configureable: true,
get: function () {
return bValue;
},
set: function (newValue) {
bValue = newValue;
}
});
//define the prototype function clear to clear the data
Object.defineProperty(Array.prototype, "clear", {
enumerable: false,
writable: false,
value: function () {
this.storage = this.slice(0); //copy the data to the storage
for (var p in this) {
if (this.hasOwnProperty(p)) {
delete this[p]; //delete the data
}
}
return this; //return the object if you want assign the return value
}
});
//define the prototype function restore to reload the data
Object.defineProperty(Array.prototype, "restore", {
enumerable: false,
writable: false,
value: function () {
var a = this.storage.slice(0); //copy the storage to a local var
for (var p in this.storage) {
if (this.storage.hasOwnProperty(p)) {
this[p] = a[p]; //assign the pointer to the new variable
delete this.storage[p]; //delete the storage
}
}
return this;
}
});
var a = ['f','o','o'];
console.log(a); //--> displays ['f','o','o']
a.clear();
console.log(a); //--> displays []
a.restore();
console.log(a); //--> displays ['f','o','o']

You can use splice() method to delete all elements of an array likes below
function clearArray(a){
storeArray = a;
a.splice(0,a.length);
}

var a = [1,2,3,4];
var tempArr ;
clearArray = function() {
tempArr = a.slice(0);
a.length = 0;
}
undoArray = function() {
a = tempArr.slice(0);
}
Here is a small jsfiddle: http://jsfiddle.net/66s2N/

Here's working way of what you want to achieve:
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a.slice(0);
for (var i=0; i<a.length; i++)
delete a[i];
a.length = 0;
}
function undoClearArray(a){
for (var i=0; i<storeArray.length; i++)
a.push(storeArray[i]);
}
console.log(foo);
clearArray(foo);
console.log(foo); //now foo is []
undoClearArray(foo);
console.log(foo); // now foo is ['f','o','o']
http://jsfiddle.net/44EF5/1/
When you do:
var a1 = [1,2,3];
a1 = [];
it's as if you've written:
var a1 = [1,2,3];
var a1 = [];
You're overwriting variables.
Now, why your approach doesn't work - in JS there's no passing by reference. MarkM response explains what's happening within the function.
Now, why does the above work - while you've got two variables pointing towards the same array, nothing prevents you from modifying that array. As such storeArray = a.slice(0) will create a copy of the array. Then by using delete we're removing all values of the array, and then as length isn't enumerable (so using for (var i in a) wouldn't help) we reassign the length of the array. This has removed the values of original array, while creating a new array assigned to storeArray.

function clearArray(a){
storeArray = a.slice(0);
return a.length = 0;
}
or set foo.length = 0;

Just update your both function with below ones
function clearArray(a){
storeArray = a.slice(0);
a.length = 0;
}
function undoClearArray(a){
a = storeArray;
return a;
}
in undoClearAray() we are returning the variable which have new reference(in your clearArray(), Both the original and new array refer to the same object. If a referenced object changes, the changes are visible to both the new and original arrays). so use it as foo=undoClearArray(foo); for old values.

try
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a;
a = [];
return a;
}
function undoClearArray(a){
a = storeArray;
}
foo = clearArray(foo);
foo; //returns []

You can use wrappers to do this quite nicely. First create a wrapper function with the additional methods defined, then create your array using that function instead of []. Here is an example (see JSFiddle):
var extendedArray = function() {
var arr = [];
arr.push.apply(arr, arguments);
arr.clearArray = function() {
this.oldValue = this.slice(0);
this.length = 0;
}
arr.undoArray = function() {
this.length = 0;
for (var i = 0; i < this.oldValue.length; i++) {
this.push(this.oldValue[i]);
}
}
return arr;
};
var a = extendedArray('f', 'o', 'o');
alert(a);
a.clearArray();
alert(a);
a.undoArray();
alert(a);

Related

Javascript Accessor properties confusion

I am not sure why this code gives me an error. All I want to do is create an object that has an array as a property. I want to achieve this with a setter and getter but for some reason when I do this.array = [] inside the setArray function I get Maximum call stack size exceeded. What am I doing wrong ? What am I missing about Javascript's accessor properties.
var obj = {
set array(size) {
this.array = [];
for (var i = 0; i < size; i++){
this.array[i] = i;
}
}
};
var myObj = Object.create(obj);
myObj.array = 20;
You're assigning to a property with a setter from within the setter, which is why it recurses forever:
var obj = {
set array(size) { // <== The property is called `array`
this.array = []; // <== This calls the setter
for (var i = 0; i < size; i++){
this.array[i] = i; // <== This would fail because there's no getter
}
}
};
You have to store the value elsewhere, for instance here we create a private scope and close over a variable:
var obj = (function() {
var array = [];
return {
set array(size) {
array = []; // No `this` here
for (var i = 0; i < size; i++) {
array[i] = i; // No `this` here
}
},
showArray() {
console.log(array);
}
};
})();
var myObj = Object.create(obj);
myObj.array = 20;
myObj.showArray();
You asked about avoiding the function. You need the function to make the value of the property truly private. But if you don't want to use it for some reason, and you're not that bothered about it being truly private, you can do what Zoltán Tamási did in his answer: Use another property on the same object. His answer uses a _ prefix on the underlying property (e.g., _array), which is a very common convention in JavaScript for "leave this alone, it's 'private'" even though there are no private properties. The fact is that even in languages with truly private properties (like Java, where they're called instance fields), there's usually some form of powerful reflection mechanism you can use to get around it, so...
If you do that, one thing to consider is whether you want that private property included in JSON if you serialize. If not, just implement toJSON as well so you can control which properties are included during serialization:
var obj = {
_array: [],
foo: "a value to include in JSON",
set array(size) {
this._array = []; // Note the _
for (var i = 0; i < size; i++) {
this._array[i] = i;
}
},
showArray() {
console.log(this._array);
},
toJSON() {
return {
// Here we list only the properties we want to have
// included in the JSON
foo: this.foo
};
}
};
var myObj = Object.create(obj);
myObj.array = 20;
myObj.showArray();
console.log(JSON.stringify(myObj));
You are using the setter inside the setter itself when you write this.array = []. Introduce another member called for example _array and fill that in the setter of the array property.
var obj = {
_array: [],
set array(size) {
for (var i = 0; i < size; i++){
this._array[i] = i;
}
}
};
var myObj = Object.create(obj);
myObj.array = 20;
You had mentioned that you wanted to use setters and getters, this snippet just uses obj.array instead of showArray to view the object's array.
var obj = (function() {
var _array = [];
return {
get array(){
return _array;
},
set array(size) {
_array = [];
for (var i = 0; i < size; i++) {
_array[i] = i;
}
}
};
})();
obj = Object.create(obj);
obj.array = 20;
console.log(obj.array);

Convert an array into an object in JavaScript

Exists a more elegant way to create an object from an array than this one?
var createObject = function(){
var myArray= generateArray();
var myObject = {
question : myArray[0],
answerA : myArray[1],
answerB : myArray[2],
answerC : myArray[3],
answerD : myArray[4]
};
return myObject;
}
What's your background? Python?
var values = generateArray();
var obj = {};
["question", "answerA", "answerB", "answerC", "answerD"].forEach(function(item, idx) {
obj[item] = values[idx];
});
return obj;
You could define an attribute map:
var createObject = function(){
// The map should have the attribute names set in order defined in `myArray`
var map = ["question", "answerA", "answerB", "answerC", "answerD"]
var myArray = generateArray();
var myObject = {};
for(var i in map)
myObject[map[i]] = myArray[i];
return myObject;
}
Try this to go beyond 'A', 'B', 'C', 'D':
function arrayToObject ( array ) {
return array.reduce(
function ( object, cell, index ) {
if (index > 0) object['answer' + String.fromCharCode(64 + index)] = cell;
else object['question'] = cell;
return object;
}, {}
);
}
If you would like to have a function that takes an array as an argument, and returns an object, this is how I would do it:
var toObject = function(arr) {
var newObj = {};
for(var i = 0; i < arr.length; i++) {
newObj[i] = arr[i];
}
return newObj;
};
However, keep in mind that Javascript arrays are simply objects with more methods available to them such as push(), pop(), and the length property.
Hope this helps!

Javascript class with array can't get length

I have a custom javascript class that contains an array, when I add a method to return the length, it is always 0. I'm sure its something I'm missing.. any ideas?
http://jsfiddle.net/ypWsZ/1/
function MyObject(){
this.name='';
}
var selected = (function(){
var arr = new Array();
return {
add : function(s){
arr.push(s);
},
length: function(){
return arr.length;
}()
};
})();
$(document).ready(function(){
var obj = new MyObject();
obj.name = 'test';
selected.add(obj);
selected.add(obj);
alert(selected.length);
});
length: function(){
return arr.length;
}()
Typo: length is the result (0) of invoking an anonymous function. Remove the () at the end and use:
alert(selected.length());

Set length property of JavaScript object

Let's say I have a JavaScript object:
function a(){
var A = [];
this.length = function(){
return A.length;
};
this.add = function(x){
A.push(x);
};
this.remove = function(){
return A.pop();
};
};
I can use it like so:
var x = new a();
x.add(3);
x.add(4);
alert(x.length()); // 2
alert(x.remove()); // 4
alert(x.length()); // 1
I was trying to make .length not a function, so I could access it like this: x.length, but I've had no luck in getting this to work.
I tried this, but it outputs 0, because that's the length of A at the time:
function a(){
var A = [];
this.length = A.length;
//rest of the function...
};
I also tried this, and it also outputs 0:
function a(){
var A = [];
this.length = function(){
return A.length;
}();
//rest of the function...
};
How do I get x.length to output the correct length of the array inside in the object?
You could use the valueOf hack:
this.length = {
'valueOf': function (){
return A.length;
},
'toString': function (){
return A.length;
}
};
Now you can access the length as x.length. (Although, maybe it's just me, but to me, something about this method feels very roundabout, and it's easy enough to go with a sturdier solution and, for example, update the length property after every modification.)
If you want A to stay 'private', you need to update the public length property on every operation which modifies A's length so that you don't need a method which checks when asked. I would do so via 'private' method.
Code:
var a = function(){
var instance, A, updateLength;
instance = this;
A = [];
this.length = 0;
updateLength = function()
{
instance.length = A.length;
}
this.add = function(x){
A.push(x);
updateLength();
};
this.remove = function(){
var popped = A.pop();
updateLength();
return popped;
};
};
Demo:
http://jsfiddle.net/JAAulde/VT4bb/
Because when you call a.length, you're returning a function. In order to return the output you have to actually invoke the function, i.e.: a.length().
As an aside, if you don't want to have the length property be a function but the actual value, you will need to modify your object to return the property.
function a() {
var A = [];
this.length = 0;
this.add = function(x) {
A.push(x);
this.length = A.length;
};
this.remove = function() {
var removed = A.pop();
this.length = A.length;
return removed;
};
};
While what everyone has said is true about ES3, that length must be a function (otherwise it's value will remain static, unless you hack it to be otherwise), you can have what you want in ES5 (try this in chrome for example):
function a(){
var A = [],
newA = {
get length(){ return A.length;}
};
newA.add = function(x){
A.push(x);
};
newA.remove = function(){
return A.pop();
};
return newA;
}
var x = a();
x.add(3);
x.add(4);
alert(x.length); // 2
alert(x.remove()); // 4
alert(x.length); // 1
You should probably use Object.create instead of the function a, although I've left it as a function to look like your original.
I don't think you can access it as a variable as a variable to my knoledge cannot return the value of a method, unless you will hijack the array object and start hacking in an update of your variable when the push/pop methods are called (ugly!). In order to make your method version work I think you should do the following:
function a(){
this.A = [];
this.length = function(){
return this.A.length;
};
this.add = function(x){
this.A.push(x);
};
this.remove = function(){
return this.A.pop();
};
};
These days you can use defineProperty:
let x = {}
Object.defineProperty(x, 'length', {
get() {
return Object.keys(this).length
},
})
x.length // 0
x.foo = 'bar'
x.length // 1
Or in your specific case:
Object.defineProperty(x, 'length', {
get() {
return A.length
}
})
function a(){
this.A = [];
this.length = function(){
return this.A.length;
};
this.add = function(x){
this.A.push(x);
};
this.remove = function(){
return this.A.pop();
};
};

My array data is being corrupted somehow by my custom (Set Theory) Complements() function?

I was fed up with the limited javascript Array functions and wanted to write a few of my own handy prototype functions to perform Set Theory functions.
Below is the code I have for this so far
<script type="text/javascript">
Array.prototype.contains = function(obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
return true;
}
}
return false;
}
Array.prototype.getIndices = function(obj){
var indices = new Array();
var i = this.length;
while (i--) {
if(this[i] === obj){
indices.push(i);
}
}
return indices;
}
Array.prototype.Union = function(arr){
//combines two arrays together to return a single array containing all elements (once)
//{1,2,3,4,5}.Union({3,4,5,6,7})
//returns: {1,2,3,4,5,6,7}
var primArray = this;
var secondArray = arr;
var i = primArray.length;
while(i--){
if(secondArray.contains(primArray[i])){
primArray.splice(i, 1);
}
}
var returnArr = primArray.concat(secondArray);
return returnArr;
}
Array.prototype.Intersection = function(arr){
//Returns an array of elements that are present in both sets
//{1,2,3,4,5}.Intersection({3,4,5,6,7})
//returns: {3,4,5}
var primArray = this;
var secondArray = arr;
var returnArr = new Array;
var i = 0;
while(i++<primArray.length){
if(secondArray.contains(primArray[i])){
returnArr.push(primArray[i]);
}
}
return returnArr;
}
Array.prototype.Complement = function(arr){
//Returns an array of elements that are only in the primary (calling) element
//{1,2,3,4,5}.Complement({3,4,5,6,7})
//return: {1,2}
var primArray = this;
var secondArray = arr;
var i = primArray.length;
while(i--){
if(secondArray.contains(primArray[i])){
primArray.splice(i, 1);
}
}
return primArray;
}
Array.prototype.SymmetricDifference = function(arr){
//Returns elements that are exclusive to each set
//{1,2,3,4,5}.SymmetricDifference({3,4,5,6,7})
//return: {1,2,6,7}
var primArray = this;
var secondArray = arr;
var i = primArray.length;
while(i--){
if(secondArray.contains(primArray[i])){
var indices = secondArray.getIndices(primArray[i]);
primArray.splice(i, 1);
var j=indices.length;
while(j--){
secondArray.splice(indices[j], 1);
}
}
}
var returnArr = primArray.concat(arr);
return returnArr;
}
function run(){
var Q = "A";
var D = [1,2,3,4,5,6,7,8,9,10];
var sets = {
"A":[1,2,3],
"B":[3,4,5],
"C":[5,6,7]
}
var R = D;
for(var el in sets){
R = R.Complement(sets[el]);
}
//if I alert D at this point I get 8,9,10 instead of 1,2,3,4,5,6,7,8,9,10 as I would expect? What am I missing here... It causes a problem when I perform D.Complement(R) later on
document.write(R + "<br/>");
R = R.Union(sets[Q]);
document.write(R + "<br/>");
//Here!
R = D.Complement(R);
document.write(R);
}
</script>
</head>
<body onload="run()">
</body>
</html>
Everything is working up to the final point when I then try to get the complement of the domain and my newly constructed set. I am expected to be getting the complement of [1,2,3,4,5,6,7,8,9,10] and [8,9,10,1,2,3] which would yield [4,5,6,7] but when I perform D.Complement(R) my D variable seems to have turned into [1,2,3]. This appears to happen after the enumeration I perform.
I thought it might be because I was using this.splice and arr.splice in my functions and when I was passing the variables to the functions they were being passed as pointers meaning I was actually working on the actual memory locations. So I then used primArray and secondArray to create a duplicate to work on... but the problem is still happening
Many Thanks
So I then used primArray and secondArray to create a duplicate to work on... but the problem is still happening
Just assigning it to a variable does not make it a new array, you are still working on the array that was passed in. You have to manually make a new copy of the array either by looping through it and copy each index or by joining and splitting.

Categories

Resources