0

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?

5
  • Shouldn't you change for (x = 0, subscribers.length || 0; x < length; x += 1) { to for (x = 0; subscribers.length == 0 || x < subscribers.length; x += 1) { Commented Sep 14, 2016 at 23:06
  • Why do you think subscribers is an array? It seems to be undefined. Commented Sep 14, 2016 at 23:06
  • it is undefined if it's unpopulated, right no, it's zero. Makes sense - there are zero objects in the array, hence the length is zero. Commented Sep 14, 2016 at 23:11
  • In your method you check events[eventName] and drop out if it has a value. So in the next line, it means it doesn't have a value, so subscribers is likely undefined at that point. Commented Sep 14, 2016 at 23:22
  • subscribers will always be undefined with this code. Because you return false when events[eventName] is truthy Commented Sep 14, 2016 at 23:22

4 Answers 4

3

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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?

2 Comments

I forgot to add the assignment. The response is still ' length undefined'
@KenIngram how did you modify it? Are you sure events[eventName]contains an array?
0

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

Comments

-1

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);
}

2 Comments

x = 0, True ; x < undefined; x += 1 what is that "True" there? It's completely incorrect whatever it is - the result of subscribers.length || 0 will always be equal to the current length (in case the length is 0 it will proceed with the OR and still return 0). However, that expression will be assigned to x since the comma operator is present. What would actually happen is x = subscribers.length; x < undefined; x += 1 and the check will always be false, because undefined is never going to be more than any number.
you are right to say that the expression will evaluate to 0. but how can it be assigned to x? I thought js will simply evaluate the expression.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.