1

Trying to create a wrapper class for Array, implementing event listeners. Previously, I used a static list of Array methods, but now I want it to be dynamic, so I'm trying to loop over Array.prototype. After searching Google for a bit, I found one on this site that said to use Object.getOwnPropertyNames, which does work... kind of. Here's my code. Debugging the properties works, but doesn't in practice.

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define([], factory);
  } else if (typeof module === 'object' && module.exports) {
    module.exports = factory();
  } else {
    root.Stack = factory();
  }
}(this || window || {}, function() {
  var Stack = function(stack) {
    if (!(this instanceof Stack)) {
      var self = Object.create(Stack.prototype);
      Stack.apply(self, arguments);
      return self;
    } else {
      if (stack instanceof Array) {
        if (arguments.length > 1) {
          Array.prototype.concat.apply(this.stack = [], arguments);
        } else {
          this.stack = stack;
        }
      } else if (Object.prototype.toString.call(stack) === '[object Object]') {
        this.stack = [];
        if (arguments.length > 1) {
          for (var i = 0; i < arguments.length; i++) {
            for (var j in arguments[i]) {
              if (arguments[i].hasOwnProperty(j)) {
                this.stack.push(arguments[i][j]);
              }
            }
          }
        } else {
          for (var key in stack) {
            if (stack.hasOwnProperty(j)) {
              this.stack.push(stack[key]);
            }
          }
        }
      } else {
        Array.prototype.push.apply(this.stack = [], 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.bind(this.stack));
      return this;
    },
    trigger: function(event, args) {
      this.events[event].forEach(function(callback) {
       callback(args);
      });
      return this;
    },
    off: function(event, callback) {
      this.events[event].splice(this.events[event].indexOf(callback), 1);
      return this;
    }
  };
  var proto = Object.getOwnPropertyNames(Array.prototype),
      method;
  for (method in proto) {
    method = proto[method];
    if (typeof Array.prototype[method] === 'function') {
      Stack.prototype.events[method] = [];
      Stack.prototype[method] = function() {
        return this.trigger(method, Array.prototype[method].apply(this.stack, arguments));
      }
    }
  }
  return Stack;
}));

method, when logged, gives the name of the method, and one can then access the function itself with Array.prototype[method], but the following example does not work and used to when I was using a list.

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

Am I not accessing the prototypical methods correctly? How would I get this to function dynamically?

Raiden
  • 311
  • 3
  • 17
  • 2
    Define "does not work". You're getting errors? You're getting an unexpected result? Something else? –  Mar 21 '16 at 18:42
  • Absolutely nothing -- no console errors, no output, nothing. – Raiden Mar 21 '16 at 18:47
  • maybe the condition did not get fulfilled and it didnt enter the code block? – Gokigooooks Mar 21 '16 at 19:00
  • 1
    You've got the standard closure-in-a-loop problem. `method` is scoped outside of your loop. – Bergi Mar 21 '16 at 19:23
  • 1
    Also `getOwnPropertyNames` returns an array, and you [shouldn't use `for in` enumerations on those](http://stackoverflow.com/q/500504/1048572). Go for `.forEach` and both your problems are solved. – Bergi Mar 21 '16 at 19:24
  • 1
    And btw, your `for (var key in stack)` is a very bad idea. Not only do objects not posess any order, so that your stack is basically ordered randomly, but this also prevents you from creating a stack of objects. – Bergi Mar 21 '16 at 19:25
  • forEach didn't work, so I wrapped the code in my loop with a closure and it worked like a charm. I realize for... in loops are a bad idea for Arrays so I will look into an alternative for that once I'm off my tablet, and as for the one in the constructor... do you have any ideas on how to get around that? – Raiden Mar 22 '16 at 00:20

0 Answers0