0

Using RequireJS, I've build a small script. Depending on what is passed to a function, another file gets required – so it's something like a real simple factory probably. Imagine it like this:

function MyThing(a) {
    if (a > 2) {
        this.script = require['lib1'];
    } else {
        this.script = require['lib2'];
    }
}

I other languages (I am coming from PHP), I can implement the same interface in both classes and be sure that lib1 and lib2 both share the functions defined in the interface.

If it worked like that in JavaScript, down the road I could call this.script.getId() or something like that and it would just work, no matter if lib1 or lib2 would be used.

Unfortunately, there are no interfaces in JavaScript (this Answer explained very well why it wouldn't make sense), so I am a bit stuck on how I should deal with it.

Of course I could create something like an interface that maps to both libs, but I have the feeling this would be the wrong way to deal with it.

What is the right approach towards the problem I am encountering?

Community
  • 1
  • 1
Sven
  • 12,997
  • 27
  • 90
  • 148
  • What exactly is the problem? What is it that you need to "deal with"? In JavaScript, an object is an object. Just make sure that your objects have some common set of properties and you're OK. – Pointy May 02 '15 at 18:25
  • @Pointy Exactly that is the problem – in other languages I could make sure that there are some common properties using an interface. Conformance would be forced through a feature of the language. In JavaScript, it's just a developer's good will ;-) – Sven May 02 '15 at 18:29
  • Yes, that's the nature of JavaScript. – Pointy May 02 '15 at 18:32
  • @Sven: Then use typescript or something else that will let you do type-checking and interface conformance, and compiles to js – Bergi May 02 '15 at 18:52

1 Answers1

2

You can just use duck typing, which exploits the fact that JS can convert anything and everything into a boolean value. If a function exists, its coerced boolean is true, so:

var lib = doMagicLoading();

// does the lib support the function we need?
if (lib.functionINeed) {
  // it does, so we can simply move on along our intended code path.
  lib.functionINeed();
} else {
  // if it does not, that might be a problem, or it might not be. Warn us:
  console.warn("library does not implement the function I Need...");
}

This is also how JavaScript code makes sure it does "the right thing" on different browsers that support different versions of JS, for instance. Step 1: test whether the function exists. Step 2: call it if does, or do something else if it doesn't.

Of course, in your case, as the programmer responsible for having working code you can actually guarantee well behaved code, because of course you wrote tests for your scripts, to make sure both code paths do the right thing, and you bundled your code using r.js before deploying. If not: it's time to start writing tests. Don't just trust developers to write working code -- that includes yourself =)

Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
  • Quack. Quack. Quack. This term makes me giggle every time. – jdphenix May 02 '15 at 18:26
  • @Mike'Pomax'Kamermans I understand, the tests would make sure everything is correct. Do you think it's reasonable to do something like this? – Sven May 02 '15 at 19:12
  • If you want code that you can trust, then having tests for non-deterministic-at-runtime code is plain old necessary. You can't guarantee which path will be taken, so you write code that makes sure to test both. And then if you want true integrity, you also set up your version control so that you can't even merge code that fails tests (easier than it sounds if you use something like Github with TravisCI) – Mike 'Pomax' Kamermans May 02 '15 at 19:20