3

Trying to create a wrapper class for Array which enhances it with event listeners. Here's an example of its usage:

new Stack(1, 2, 3).on('push', function (length) {
  console.log('Length: ' + length + '.');
}).push(4, 5, 6);

Here's my code (fiddle):

(function(window, undefined) {
  window.Stack = function(stack) {
    if (!(this instanceof Stack)) {
      throw new TypeError('Stack must be called with the `new` keyword.');
    } else {
      if (stack instanceof Array) {
        this.stack = stack;
      } else {
        Array.prototype.push.apply(this.stack = [], Array.prototype.slice.call(arguments));
      }
      Array.prototype.push.apply(this, this.stack);
      this.length = this.stack.length;
    }
  };
  Stack.prototype = {
    events: {

    },
    on: function(event, callback) {
      this.events[event].push(callback);
      return this;
    },
    trigger: function(event, args) {
      this.events[event].forEach(function(callback) {
        callback.call(this.stack, args);
      });
      return this;
    }
  };
  'fill pop push reverse shift sort splice unshift concat includes join slice indexOf lastIndexOf forEach every some filter find findIndex reduce'.split(' ').forEach(function(method) {
    Stack.prototype.events[method] = [];
    Stack.prototype[method] = function() {
      return this.trigger(method, this.stack[method].apply(this.stack, this.stack.slice.call(arguments)));
    };
  });
}(window));

I want to be able to instantiate Stack without using new, and usually, I would just do this:

if (!(this instanceof Stack)) {
  return new Stack(arguments);
}

But it doesn't work here, because I'm essentially passing arguments (a psuedo-array) as the first argument to... arguments.

How would I make it so I could call Stack without using new?

Raiden
  • 311
  • 3
  • 17

1 Answers1

2

You can use Object.create to create the object, then .apply() to apply the arguments.

if (!(this instanceof Stack)) {
  var t = Object.create(Stack.prototype);
  Stack.apply(t, arguments);
  return t
}

I believe ES6 allows for passing a collection of arguments with new using the spread operator, but this will cover legacy browsers.