Ken Ingram
Ken Ingram

Reputation: 1598

Is .length an appropriate call to a JavaScript array?

For some reason, I cannot get the length of an array (it is undefined if it's unpopulated, right?).

define(function() {
  'use strict';

  var self = {},
    events = {};

  self.publish = function publish(eventName, data) {
    var subscribers, x, length;

    if (events[eventName]) {
      return false;
    }

    subscribers = events[eventName];

    for (x = 0, length = subscribers.length || 0; x < length; x += 1) {
      subscribers[x](data);
    }

    return true;
  };

  self.subscribe = function subscribe(eventName, func) {
    if (!events[eventName]) {
      events[eventName] = [];
    }

    events[eventName].push(func);
  };
  return self;
});

JSLint says: "Expected ';' and instead saw ','." Jasmine says "TypeError: Cannot read property 'length' of undefined"

Why isn't length set to 0? Have I misunderstood the syntax an operations here?

Upvotes: 0

Views: 81

Answers (4)

Ken Ingram
Ken Ingram

Reputation: 1598

As it turns out, the code worked fine when I fixed the typo.

if (events[eventName]) {

is supposed to be

if (!events[eventName]) {

Everything worked as intended after that correction. My debugging issues are always something stupidly minor

Upvotes: 0

vdj4y
vdj4y

Reputation: 2669

like Don Bhrayan Singh said

your code should be

for (var x = 0, length = subscribers.length || 0; x < length; x += 1) {
  subscribers[x](data);
}

your previous code will run like this

// x = 0,           0           ; x < undefined; x += 1
for (x = 0, subscribers.length || 0; x < length; x += 1)     {
  subscribers[x](data);
}

Upvotes: -1

Tamas Hegedus
Tamas Hegedus

Reputation: 29906

You are missing a negation in the publish function:

self.publish = function publish(eventName, data) {
    var subscribers, x, length;

    if (events[eventName]) { // <= Here you exit if there are subscribers, and continue if there arent
      return false;
    }

    subscribers = events[eventName];  // So subscribers is guaranteed to be undefined

    // can't get length (or any property) of undefined
    for (x = 0, length = subscribers.length || 0; x < length; x += 1) {
...

This causes your tests to fail. This is the way to go:

self.publish = function publish(eventName, data) {
    // you can use const and let
    // you are storing subscribers in a variable anyway, so why not doing it
    // before the check?
    const subscribers = events[eventName];

    if (!subscribers) {
      return false;
    }

    // you don't need to cache length in a variable, iirc it only improves performance slightly on IE browsers
    // neither need you `|| 0`
    // there other ways iterating through an array, see for..of and Array.prototype.forEach
    for (let x = 0; x < subscribers.length; x++) {
      subscribers[x](data);
    }

    return true;
};

it is undefined if it's unpopulated, right?

No, the length of an array is zero if its empty. You get an undefined when reading a missing property of an object, but the length of an array is always a number.

Upvotes: 3

Don Bhrayan Singh
Don Bhrayan Singh

Reputation: 475

I think the problem is with this line:

for (x = 0, subscribers.length || 0; x < length; x += 1) {

you defined the variable "length" but never initialized / assigned data to it.

In detail:

subscribers.length || 0

Whats this supposed to do?

x < length

x < length or x < subscribers.length?

Upvotes: 0

Related Questions