3
\$\begingroup\$

The reason why I want to have something like this is to be able to add custom methods/props to certain arrays only. I came up with this little object that works well but I'm wondering if you guys have better way.

(function (scope) {
    var target = scope || window;
    target.Hurray = function() { 
        this.length = 0;
        this.count = 0;
        var _arr = Array.prototype.slice.call(arguments);
        this.reset = function() {
            for (var prop in this) {
                if (!isNaN(prop)) {
                    this[prop] = undefined;
                    try {
                        delete this[prop];
                    } catch(e) {
                    }
                }
            }
            for (var x = 0; x < _arr.length; x++) {
                this[x] = _arr[x];
            }
            this.length = _arr.length;
            this.count = this.length;
        };
        this.reset();
        this.toArray = function() {
            return _arr;
        };
        this.concat = function() {
            _arr.concat.apply(_arr, arguments);
            this.reset();
            return this;
        };
        this.indexOf = function() {
            var index = _arr.indexOf.apply(_arr, arguments);
            this.reset();
            return index;
        };
        this.join = function() {
            var rtn = _arr.join.apply(_arr, arguments);
            this.reset();
            return rtn;
        };
        this.lastIndexOf = function() {
            var index = _arr.reverse().indexOf.apply(_arr, arguments).reverse();
            return index;
        };
        this.pop = function() {
            var elem = _arr.pop.apply(_arr, arguments);
            this.reset();
            return elem;
        };
        this.push = function() {
            var elem = _arr.push.apply(_arr, arguments);
            this.reset();
            return elem;
        };
        this.reverse = function() {
            _arr.reverse.apply(_arr, arguments);
            this.reset();
            return this;
        };
        this.shift = function() {
            var elem = _arr.shift.apply(_arr, arguments);
            this.reset();
            return elem;
        };
        this.slice = function() {
            return _arr.slice.apply(_arr, arguments);
        };
        this.sort = function() {
            _arr.sort.apply(_arr, arguments);
            this.reset();
            return this;
        };
        this.splice = function() {
            _arr.splice.apply(_arr, arguments);
            this.reset();
            return this;
        };
        this.toString = function() {
            return _arr.toString.apply(_arr, arguments);
        };
        this.unshift = function() {
            _arr.concat.apply(_arr, arguments);
            this.reset();
            return this.length;
        };
        this.valueOf = function() {
            return _arr.concat.apply(_arr, arguments);
        };
        this.add = function() {
            return this.push.apply(this, arguments);
        };
        this.removeAt = function(index) {
            return this.splice(index, 1);
        };
        this.find = function(value, caseInsensitive) {
            var rtn = new Hurray();
            if (!caseInsensitive) {
                for (var x = 0; x < this.length; x++) {
                    var currval = this[x];
                    if (currval == value)
                        rtn.push(currval);
                }
            } else {
                value = value.toString().toLowerCase();
                for (var x = 0; x < this.length; x++) {
                    var currval = this[x].toString().toLowerCase();
                    if (currval == value)
                        rtn.push(currval);
                }
            }
        };
        this.findByProperty = function(key, value, caseInsensitive) {
            var rtn = new Hurray();
            if (!caseInsensitive) {
                for (var x = 0; x < this.length; x++) {
                    var currval = this[x][key];
                    if (currval == value)
                        rtn.push(currval);
                }
            } else {
                value = value.toString().toLowerCase();
                for (var x = 0; x < this.length; x++) {
                    var currval = this[x][key].toString().toLowerCase();
                    if (currval == value)
                        rtn.push(currval);
                }
            }
        };
        this.replace = function() {
            var args = Array.prototype.slice.call(arguments);
            args.splice(1, 1, 0); // Add 1 as the delete parameter
            return this.splice.apply(this, args);
        };
        this.insert = function() {
            var args = Array.prototype.slice.call(arguments);
            args.splice(1, 0, 0); // Add 0 as the delete parameter
            return this.splice.apply(this, args);
        };
        this.addRange = function() {
            return this.concat.apply(this, arguments);
        };
        this.insertRange = function() {
            var arrays = Array.prototype.slice.call(arguments);
            var index = arrays.splice(0, 1);
            for (var x = 0; x < arrays.length; x++) {
                for (var k = 0; k < arrays[x].length; k++) {
                    _arr.splice(index++, 0, arrays[x][k]);
                }
            }
            this.reset();
            return this;
        };
        this.getRange = function() {
            return this.concat.slice(this, arguments);
        };
        this.remove = function(value, onlyFirstFind) {
            var index = _arr.indexOf(value);
            if (index == -1) return this;
            _arr.splice(index, 1);
            index = _arr.indexOf(value);
            if (!onlyFirstFind) {
                while (index != -1) {
                    _arr.splice(index, 1);
                    index = _arr.indexOf(value);
                }
            }
            this.reset();
            return this;
        };
        this.clear = function() {
            _arr = [];
            this.reset();
            return this;
        };
        this.contains = function(value, caseInsensitive) {
            if (!caseInsensitive) {
                return this.indexOf(value) != -1;
            } else {
                var value = value.toString().toLowerCase();
                for (var x = 0; x < this.length; x++) {
                    if (this[x].toString().toLowerCase() == value) {
                        return true;
                    }
                }
            }
            return false;
        };
        this.each = function(callback) {
            for (var x = 0; x < _arr.length; x++) {
                var newVal = callback.apply(this, [_arr[x]]);
                if (newVal)
                    _arr[x] = newVal;
            }
            this.reset();
            return this;
        };
        this.toHurray = function() {
            return this;
        };


    };
    Array.prototype.toHurray = function () {
        return new Hurray().concat(this);
    };
})();  //scope goes here!
\$\endgroup\$
1
  • 2
    \$\begingroup\$ What's wrong with using regular arrays? How many do you have? \$\endgroup\$ Commented May 25, 2012 at 19:35

1 Answer 1

9
\$\begingroup\$

If you don't need the magic .length property, then how about making a constructor function whose prototype is an object that inherits from Array.prototype?

function Hurray() {}

Hurray.prototype = Object.create(Array.prototype);

var h = new Hurray;
h.push('a','b','c');

alert(h.length); // 3

var last = h.pop();

alert(last); // 'c'
alert(h.length); // 2

And add your custom methods to Array.prototype Hurray.prototype as you need. (Thanks to Bill Barry for spotting my mistake!)

The way you're doing it right now, you're not taking any advantage of inheritance, but instead are creating a bunch of duplicate functions every time a new object is created.


If you don't want the original Array methods, you could still use prototypal inheritance for your methods, and use the Array.prototype methods under the hood.

var _arr_proto = Array.prototype;

function Hurray() {}
Hurray.prototype.length = 0;

Hurray.prototype.add = function() {
    _arr_proto.push.apply(this, arguments);
    return this;
};
Hurray.prototype.removeFromEnd = function() {
    _arr_proto.pop.apply(this, arguments);
    return this
};
\$\endgroup\$
2
  • 2
    \$\begingroup\$ just one small nit, don't modify Array.prototype, modify Hurray.prototype. \$\endgroup\$
    – Bill Barry
    Commented May 29, 2012 at 15:25
  • \$\begingroup\$ @BillBarry: Ah, I didn't see it at first, but you're talking about my sentence... "...add your custom methods to Array.prototype as you need", and you're absolutely correct. That was a flub... should have said Hurray.prototype. Thanks for spotting it! \$\endgroup\$
    – user10711
    Commented May 29, 2012 at 15:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.