Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Having trouble understanding a reflection test in Javascript Koans

There is already an answer posted to the test itself, which can be found here, but I can't seem to figure out why that answer is correct.

The part of the test that is giving me trouble is:

var keys = [];
var fruits =  ['apple', 'orange'];
for(propertyName in fruits) {
    keys.push(propertyName);
}
ok(keys.equalTo(['__', '__', '__']), 'what are the properties of the array?');

The (apparently) correct answer, as noted in the above linked question is

ok(keys.equalTo(['0', '1', 'fruits.prototype'), 'what are the properties of the array?');

I tried inserting the answer - fixed the syntax error - and my test still fails.

In the same test file, another test is nearly identical and the answer is what I would expect it to be:

test("property enumeration", function() {
    var keys = [];
    var values = [];
    var person = {name: 'Amory Blaine', age: 102, unemployed: true};
    for(propertyName in person) {
        keys.push(propertyName);
        values.push(person[propertyName]);
    }
    ok(keys.equalTo(['name','age','unemployed']), 'what are the property names of the object?');
    ok(values.equalTo(['Amory Blaine',102,true]), 'what are the property values of the object?');
});

The only difference I can see between these two tests is that the second is using an object rather than an array.

I ran the code from the first test by itself (outside of the unit testing framework) and output the value of keys, which it showed as ["0","1"] - what I would expect. Where is this hidden third value, and how can I access it?

So, I guess I ultimately have two questions:

  1. Why is the answer from the other question not working for me?
  2. What is different about the first test and the second test?
like image 424
Sean Walsh Avatar asked Nov 04 '22 05:11

Sean Walsh


1 Answers

Disclaimer: I'm pretty sure this is right, but haven't bothered testing it. Could you try my answer out, since you've got the tests running?

Looking at the files on GitHub, there is a helper script called koan.js. I'm assuming it gets loaded before the tests because I am too lazy to run them myself :P. (It's in the support directory.)

In this file, there is a method called equalTo defined on all arrays:

Array.prototype.equalTo = function(compareTo) { ... }

So the answers to your questions:

  1. Because the answer to the other question was wrong. Completely misguided. Etc.
  2. Because the method is defined on Array rather than Object.

Seems a little bit underwhelming.

If you define a function like this on the prototype, it will be inherited by all arrays. Try defining something like that in the console and then evaluate [].equalTo. And then, for more fun, try something like:

for (x in []) console.log(x)

Since this method is defined on the prototype, the loop iterates over it as well. So the answer is to the test is probably 0, 1, 'equalTo'. However, if you use the for loop with the hasOwnProperty check, it will naturally not iterate over the method.

This is really an object lesson about no using for in to iterate over arrays :). You never know what's going to sneak in... Coincidentally, this is why prototype.js fell out of favor despite actually being a nice framework.

like image 102
Tikhon Jelvis Avatar answered Nov 07 '22 21:11

Tikhon Jelvis