2 Comments

Properties Behaving like Functions in JavaScript

My pair and I were looking into Chai, a BDD / TDD assertion library for JavaScript, and noticed a very interesting syntax. In many places, where a method took no arguments, Chai removed the need for parentheses.

For example, to verify a listener has been called looks like this:

1
listener.should.have.been.calledOnce

Or testing that something is truthy:

1
2
3
4
5
expect('everthing').to.be.ok;
expect(1).to.be.ok;
expect(false).to.not.be.ok;
expect(undefined).to.not.be.ok;
expect(null).to.not.be.ok;

At first we weren’t sure how this was done. JavaScript requires parentheses (or so we thought) to invoke a function. Leaving the parentheses off should return the property.

Looking into the source, we found that Chai was using the defineProperty method in JavaScript to create a property that acted like a function.

If you’re unfamiliar with the defineProperty call, try Understanding “Prototypes” in JavaScript by Yehuda Katz.

This pattern can be nice and make syntax slightly more natural to read, but it also carries some gotchas. Since a property is being referenced and not a function, it is important to check spelling and the existence of the property. For example, if you were to run:

1
expect(true).to.be.notActuallyAProperty;

There would be no failure. With that in mind, this pattern should be used with care in order to prevent unintended consequences.