A Look Inside JavaScript by a Java Developer

I’ve been a web developer for nine-months!

Emma Suzuki
Capital One Tech
8 min readJun 15, 2017

--

Before this, I was an Android/iOS developer for five years and have developed in Java and Swift which are both compiler-based languages. But in the last nine months I have been coding in JavaScript which is a runtime-based language.

These languages have some characteristic differences. Following is a small list of those that I have found most interesting as I make the switch to web development.

1. Static-Typing vs Dynamic-Typing

Java is a static-typed language which compiles code into JVM byte code, then interprets it into machine language. Conversely, JavaScript is a dynamic-typed language which interprets code at runtime. What does this mean in practice?

Think about this example in both languages:

Java

Javascript

The Java code above won’t compile due to type mismatch. Java tells you that you are doing something wrong right away to prevent a trivial error before you run your code.

The JavaScript code above doesn’t let you know that something could be wrong. It may look fine to you at a glance though, so let’s think about what this code prints out.

When price is 10.0 and shipping[state] returns 2.0, then console.log prints out 12.0. What if shipping[state] returns “2.0”? Now console.log prints out “102.0”.
We have no guarantee of what this code results in until we run it.

With a compiler-based language such as Java, you pay with effort upfront to fix possible errors and reduce the chances of errors at runtime. In this way, passing the compiler is like a kind of unit test that you need to pass to validate your logic. Whereas with runtime-based languages such as JavaScript, you won’t realize errors until runtime. To prevent them you need to write more tests to ensure you will get less runtime errors.

2. Monkey Patching vs No Monkey Patching

One of the features of JavaScript is that you can modify the behavior of a function on the fly; this technique is called Monkey Patching. That is to say, without having any modification to the application code, you can swap the implementation of a dependency.

In Java, since code must be compiled, every class and function definition must be defined(not mutable) before running the code. Dependency injection must be in place to be able to swap the behavior prior to running the code.

Let’s see this in an example. Let’s say I have a class called order.js and I test a function in order.js using Jest.

order.js

You can see shipping and tax are local dependencies that are required and used inside of this file. And here is the test.

order-test.js

In this test file I am overriding the implementation of shipping.fee and tax.get with Jest’s function without having any special code in order.js. When order.totalPrice is run after that line, shipping.fee and tax.get are not order.js’s implementation. Instead, it becomes Jest’s implementation. This is partially thanks to the Jest framework; yet the bottom line is that JavaScript can override the behavior of functions on the fly.

In Java, the same test is not as thin as in JavaScript. Java is a compiler-based language so all functionality is bound to what I define and is not interchangeable in runtime. Therefore, if I write tests for a class which has local dependencies, I have to either make the class accept the dependencies through public functions or use a dependency injection framework to handle the dependencies.

To demonstrate this, I will rewrite the above JavaScript test example using the dependency injection framework for Java called Dagger.

I’ll use JUnit for Java testing. The testing scenario is the same as the JavaScript example above. I have a class called Order.java and I test a function in Order.java.

First, the Order class needs to be written in such a way that it is dependency-injectable.

Order.java

@Inject is the Dagger annotation to make a field injectable from outside this class and DaggerOrderComponent.builder().orderModule(new OrderModule()).build().inject(this); will inject all @Inject annotated fields (dependencies).

Secondly, I need to prepare one class to inject production code dependencies and another class to inject test code dependencies (i.e. mocked objects) to the Order class.

OrderModule.java (for production code dependencies)

The @Module class contains a set of functions that provide dependencies to be injected. Those functions are annotated as @Provides and it returns a class that will be injected into the @Inject annotated field in the other class. For testing, I do not want to use the actual Shipping and Tax classes. Instead, I want to use mocked classes of those. Hence, I write the @Module class for testing like this:

I’ll use Mockito for generating mocked classes.

TestOrderModule.java (for test code dependency)

Now, I can inject this test module into the Order class so that I can purely test the Order class by using the mocked classes.

OrderTest.java

As you notice, Java with local dependencies requires more code to make a class testable as compared to JavaScript. Compiler-based languages like Java are not able to modify the function implementation on the fly due to its language model, as opposed to JavaScript which can dynamically alter the behavior of the functions.

3. Object-Oriented Programming vs Functional Programming

Object-oriented programming (OOP), including Java, has a concept of objects where a class defines the object’s attributes (fields) and controls those attributes (methods). The class maintains the state of the object.

Functional programming, including JavaScript, is defined by computation of data without holding state and mutating the state with functions. A function in this paradigm only depends on its inputs, and output is produced by computation based only on the inputs.

Let’s see this in a real example. Say I have a cart.js file below. This function does not hold any state, and each function only depends on its inputs.

cart.js

Since functional programming does not keep any states, “cart” needs to be always passed around.

If I translate this into Java with OOP paradigm utilizing one of the OOP’s principles -Encapsulation — I can write as below.

Cart.java

This Cart class keeps track of the properties totalPrice and items. Therefore, consumers of the class only pass the minimal information to perform operations. In the JavaScript example, however, it is possible that cart that is passed to the function would not have the same structure every time the function is called. In the Java example, the user can only perform certain operations and cannot touch properties directly.

Functional programming requires all functions to be pure functions. Thus, it is easy to test, easy to debug, and thread safe (no state at all!). However, since all functions rely on inputs, it is the consumer’s responsibility to keep track of data that is returned from functions and passed to other functions as inputs.

Object-oriented programming keeps state and encapsulates control over the state, which reduces some repetitive code and increases the reusability of code. Generally speaking, the consumer should be able to use functions without any knowledge of their implementation because complex logic/state management are hidden inside of the object that contains the function.

Conclusion

It’s been an interesting journey transitioning from mobile to web development! JavaScript and Java are two very different languages in ways I was unaware of until making the switch. I’ve listed some major differences that I found interesting, but there are many more that you could list.

Both have specific strengths, and knowing the characteristics of each will help you determine which language fits best for what case. Of course, this applies to more than just JavaScript and Java. You can apply this to any static-typing or dynamic-typing language to determine which one is good for your project. The same applies to object-oriented programming or functional programming languages. A key point is that whichever you pick, learn the characteristics and make sure you utilize its specialty!

DISCLOSURE STATEMENT: These opinions are those of the author. Unless noted otherwise in this post, Capital One is not affiliated with, nor is it endorsed by, any of the companies mentioned. All trademarks and other intellectual property used or displayed are the ownership of their respective owners. This article is © 2017 Capital One.

For more on APIs, open source, community events, and developer culture at Capital One, visit DevExchange, our one-stop developer portal. https://developer.capitalone.com/

--

--

Emma Suzuki
Capital One Tech

A bit of many technology, full of curiosity. Mobile, Web, Data Engineer.