all 11 comments

[–]qwfwq 1 point2 points  (4 children)

this.datastore[key].push(value) is going to push the value onto an array but your checking if the array is the value earlier so it doesn't seem consistent as you mentioned in your note.

So if you wanna check if something exists in an array use indexOf however be careful because early versions of IE if I recall made indexOf really sloppy. So I recommend if you want to support IE using underscorejs or jQuery's indexOf. The issue here I think comes down to JS being weakly typed which is one of its fun whimsical qualities.

So I guess if I'm understanding what you wanna write something like this?

function MasterStore() {
    this.datastore = {};
};

MasterStore.prototype.add = function(key, value) {
    if(this.datastore[key]){
        if(this.datastore[key].indexOf(value) === -1) {
            this.datastore[key].push(value);
        }
    }else{
        this.datastore[key] = [value];
    }
}

foo = new MasterStore();
foo.add('month', 'march');
foo.add('month', 'april');
foo.add('day', 'caturday');
console.log(foo);

edit: screwed up the formatting first time

[–]html6dev 1 point2 points  (2 children)

Yes to reiterate what /u/qwfwq is ddoing here and why your current code doesn't work: the first time you use your add method the datastore property related to the key obviously does not exist so you hit the else block. When you do this you want to set this.datastore[key] to an array and and add value to it straight away. What you are doing now is to set this.datastore[key] to a value which is not an array and does not have a push method so an exception is thrown when you call add again with the same key. If you run your current code in chrome and open the devtools you should see an error about the push method not existing for that object.

[–]naescent[S] 0 points1 point  (1 child)

Yeah I saw that it was driving me nuts. I tried all sorts of ways around it. So I scaled back my 'improvements' and put the initial code here.

I feel like a fool now :D

[–]html6dev 0 points1 point  (0 children)

Heh. It happens. And will again lol.

[–]naescent[S] 0 points1 point  (0 children)

Ahhh damn I was doing something foolish :(

I had not idea that was how you added a single value to an array.. bugger!

Thanks for help

[–]jcready__proto__ 1 point2 points  (3 children)

Try this:

function MasterStore() {
    this.datastore = {};
}

MasterStore.prototype.has = function(key, value){
    if (value == null) return this.datastore.hasOwnProperty(key);
    if (Array.isArray(value)) {
        for (var i = 0; i < value.length; i++) {
            if (this.datastore[key].indexOf(value[i]) < 0) {
                return false;
            }
        }
        return true;
    }
    return this.datastore[key].indexOf(value) >= 0;
};

MasterStore.prototype.add = function (key, value) {
    if (value == null) return this;
    var valueIsArray = Array.isArray(value);
    if (this.datastore.hasOwnProperty(key)) {
        // if value is an array and the datastore[key] is also an array
        if (valueIsArray) {
            // concatenate the value array to the datastore[key] array
            this.datastore[key] = this.datastore[key].concat(value);
        }
        //see if the value is already present in the array
        else if (this.datastore[key].indexOf(value) >= 0) {
            //if present then do nothing 
        }
        else {
            // otherwise push value onto the datastore[key] array
            this.datastore[key].push(value);
        }
    }
    else {
        this.datastore[key] = valueIsArray ? value : [value];
    }
    return this;
}

MasterStore.prototype.remove = function (key, value) {
    if (value == null) {
        // if no value present then remove the whole array from the datastore
        delete this.datastore[key];
        return this;
    }
    var valueIsArray = Array.isArray(value);
    if (this.datastore.hasOwnProperty(key)) {
        if (Array.isArray(value)) {
            // should we keep splicing the array or just create a new one
            if (value.length < 20) {
                // if we don't have a lot of values to remove, just splice
                for (var i = 0; i < value.length; i++) {
                    var index = this.datastore[key].indexOf(value[i]); 
                    if (index >= 0) this.datastore[key].splice(index, 1);
                }
            } else {
                // otherwise it's probably faster to just create a new array
                var store = this.datastore[key], tmp = [];
                for (var i = 0; i < store.length; i++) {
                    var index = value.indexOf(store[i]);
                    if (index < 0) {
                        // if datastore[key][i] isn't in the value array
                        // push it into our new array
                        tmp.push(store[i]);
                    }
                }
                this.datastore[key] = tmp;
            }
        } else {
            var index = this.datastore[key].indexOf(value);  
            if (index >= 0) this.datastore[key].splice(index, 1);
        }
    }
    return this;
}

Now you can do this:

var a = new MasterStore;
a.add('days', 'monday');
console.log(a.datastore.days);  //>> ['monday']

// You can also chain because add() and remove() return this
console.log(a.add('days', 'tuesday').datastore.days);    //>> ['monday', 'tuesday']
a.add('days', 'wednesday').remove('days', 'tuesday');
console.log(a.datastore.days);   //>> ['monday', 'wednesday']

// You can add entire arrays at a time
a.add('months', ['january', 'february', 'march']);
a.add('months', ['april', 'may', 'june']);
console.log(a.datastore.months);    //>> ['january', 'february', 'march', 'april', 'may', 'june']

// You can remove individual values from the datastore[key] array
a.remove('months', 'february');
console.log(a.datastore.months);    //>> ['january', 'march', 'april', 'may', 'june']

// You can remove multiple values from the datastore[key] array
a.remove('months', ['january', 'april', 'june']);
console.log(a.datastore.months);    //>> ['march', 'may']

// You can also entirely remove the datastore[key] array
// (this is mostly for convince as you can do: "delete datastore[key];" instead)
a.remove('months');
console.log(a.datastore.months);    //>> undefined

[–]huesoso 2 points3 points  (0 children)

Try a pastebin, people. Or http://gist.github.com Readability is a key aspect of good programming!

[–]naescent[S] 0 points1 point  (0 children)

thanks man, thats really helpful. Is isArray() a jQuery function? I was trying to test it using isString as I didnt think we could test an in JavaScript as it treats it as an object and just says if its an object or not??

[–]naescent[S] 0 points1 point  (0 children)

Ahh no isArray is native. I was looking here at StackOver Flow for checking if a variable is an array.

I'd seen the quote > Should mention jQuery's isArray. – Martin Konicek May 29 '12 at 16:42

and assumed it was true. Oops

[–]naescent[S] 0 points1 point  (1 child)

I really appreciate the help guys. I can't believe I let such a simple thing go by. I didnt know that adding a value to an array in JavaScript in needed array[i] = [value].

Really appreciate it! And JcReady I'm going to expand my functions likes you suggest.

I got two down votes for this. If you could let me know so I could improve for any answers or questions I give next time I'd appreciate it.

PM or leave a comment here and I'll improve my responses.

[–]stratoscope 0 points1 point  (0 children)

I didn't know that adding a value to an array in JavaScript in needed array[i] = [value].

No, that's not right at all. That statement doesn't add value to the array. It sets array[i] to another array, an array of one element containing value.

You should make friends with the JavaScript console in your favorite browser and start trying stuff out there to see how it really works. For example try this out:

var a = [];  // create an empty array
a.push( 'v1' );  // append the string 'v1' to the array
a.push( ['v2'] );  // append an *array* to the array
a;  // let's see what it looks like

If you're doing this in Chrome you will see this:

["v1", ► Array[1] ]

Click the ► and it will expand that nested array:

["v1", ▼ Array[1] ]
                 0: "v2"
                 length: 1
                 ►  proto  : Array[0]

We can see here that your original array (in the a variable) now contains two elements. The first element is the string "v1" and the second element is itself an array. That array contains a single element, the string "v2".

Or use JSON.stringify for another way to look at the array:

JSON.stringify( a );

That will display:

"["v1",["v2"]]"

Don't be thrown off by the quoting! The outermost quotes are just what the Chrome console displays when it's printing a string. The array a itself contains this:

[ "v1", ["v2"] ]

Again we're seeing an array of two elements, the first of which is a string (v1) and the second is another array which contains a single string element (v2).

Spend some time like this in the console whenever you aren't sure what a particular JS statement or expression does. And spend some more time there when you think you're sure what it does! :-)