console.log("Hello World!")
Hello World!
Christian Wittmann
October 22, 2024
I decided it was time to learn some JavaScript. Since I’m used to working in Jupyter notebooks for exploratory coding in Python, and my blog is also entirely written in Jupyter notebooks, I explored how to run a JavaScript kernel within a Jupyter notebook. While I realize this is not a common way to write JavaScript code, it’s a practical solution for embedding real JavaScript code directly into my blog posts, which are themselves built with Jupyter.
First, we will install IJavascript
, a Jupyter kernel that enables running JavaScript code directly within Jupyter notebooks. After the setup, we will explore some basics of JavaScript, and I’ll share some of my first lessons learned from using JavaScript in Jupyter notebooks, drawing comparisons to Python along the way.
IJavascript
Before we can install IJavascript
, we need to set up some basic components for JavaScript development:
While it is possible to install IJavascript
directly after setting up these components, I encountered some dependency issues during the process. To resolve these, I switched to the latest LTS (Long-Term Support) version of Node.js. At the time of writing, this step was necessary, but it may become obsolete in future versions.
Note: Everything I describe in this blog post is based on macOS. If you’re using Windows or Linux and have adapted this approach, I’d love to hear about your experience.
The Xcode Command Line Tools are a set of macOS development tools that provide essential software for compiling code and performing development tasks.
To check if they are installed, run:
If they are not installed, you can install them by running:
We will use NVM (Node Version Manager) to set up our JavaScript environment. This is the preferred method over installing via Homebrew because NVM allows you to easily switch between different versions of Node.js. Additionally, when installing IJavascript
, I encountered dependency issues with the latest version of Node.js. Therefore, we need to install the latest LTS (Long-Term Support) version of Node.js in the next step.
To check if NVM is installed, run:
If NVM is not installed, you can install it by running:
After installation, load nvm
into your current terminal session by running:
If you are new to NVM and previously installed Node.js via Homebrew, it’s recommended to uninstall the Homebrew version to avoid conflicts:
To resolve dependency issues, I switched to the latest LTS (Long-Term Support) version of Node.js. Use nvm
to install and activate this version:
You can verify the installed versions of Node.js and NPM by running:
After installing the LTS version, it’s a good idea to update npm to the latest version:
IJavascript
Once you’ve switched to the LTS version of Node.js, you can install IJavascript
by running:
The npm
command is similar to pip
in the Python world, which is used for installing packages. The -g
parameter ensures that the package is installed globally, making IJavascript
available across all projects using the active Node.js version.
After the installation, register IJavascript
as a Jupyter kernel with the following command:
After having completed all installation steps, you can run JavaScript code in a Jupyter notebook. Note that you need to restart VS Code.
When you run the following cell, you will be asked to select a kernel in VS Code. Select IJavascript
.
Let’s explore JavaScript beyond just a simple “Hello, World!”.
Unlike Python, variables in JavaScript need to be explicitly declared before they are used. Here is an example:
In the context of Jupyter notebooks, this can lead to undesired behavior where cells containing variable declarations can only be executed once. The simplest way to avoid unwanted syntax errors is to separate the declaration of variables and the actual code into two separate cells.
Since JavaScript typically declares and initializes variables at the same time (for example, let hello = "Hello";
), this separation of declaration and initialization does not feel very “JavaScripty” (similar to how “Pythonic” refers to clear and idiomatic Python code). However, this trade-off works well for using JavaScript in Jupyter notebooks, which, by itself, is not a very “JavaScripty” way of coding. Jupyter’s cell-based, interactive workflow differs significantly from how JavaScript is usually written and executed.
Here is an example to show the separation of declaration and initialization. Just be mindful not to execute the declaration cells multiple times.
By the way, notice that just like in Python, in JavaScript a string represents a sequence of characters and can be enclosed in either single quotes ('
) or double quotes ("
).
As a best practice that applies to both Python and JavaScript:
'
) by default."
) when the string contains a single quote (e.g., an apostrophe) to avoid using escape characters.Another interesting aspect of variables in JavaScript is how their scope is defined. If you declare variables using let
, the scope of the variable is limited to the block (enclosed by curly braces {}
) where it is declared. Unlike Python, this could include blocks like if
statements, for
loops, or any code wrapped in curly braces.
Here is a example:
if ('the stars align' === 'the stars align') {
let light = 'shine bright';
}
// Checking if the light still shines beyond the block
console.log(typeof light === 'undefined' ? 'The light fades into the void...' : 'The light endures.');
The light fades into the void...
Apart from the definition of the scope that we can observe in the example above, there are a few other noteworthy elements.
First, the comparison is done with ===
, which checks for strict equality. This means it checks both the value and the type, making it more precise than ==
, which only checks for value equality and can sometimes lead to unexpected results due to type coercion. (In Python, there isn’t a direct equivalent to ===
, but Python’s ==
behaves more like JavaScript’s strict ===
by default, without implicit type conversion.)
Additionally, JavaScript supports a ternary operator (just like Python, though it is more commonly used in JavaScript), which is a shorthand way of writing an if-else
statement:
JavaScript:
Python:
For completeness, here’s the traditional way of writing out the condition from the example above:
To wrap up this blog post, here’s some slightly more complex code. In parallel, I’ve been following a tutorial on building a pyramid generator in JavaScript. Below is my Jupyter notebook version, followed by some observations.
rows.length = 0; // Reset the array to an empty list
pyramidHeight = 8;
inverted = false;
result = "";
// Generates the spaces needed to center the pyramid row
function generateWhitespace(rowNumber, pyramidHeight) {
return " ".repeat(pyramidHeight - rowNumber)
}
// Generates the pyramid characters (e.g., "###" or "#####")
function generatePyramid(rowNumber){
return character.repeat(2 * rowNumber - 1)
}
// Combines whitespace and pyramid characters to create a centered row
function generatePyramidRow(rowNumber, pyramidHeight) {
const whitespace = generateWhitespace(rowNumber, pyramidHeight);
const pyramid = generatePyramid(rowNumber);
return `${whitespace}${pyramid}${whitespace}`;
}
for (let rowNumber = 1; rowNumber <= pyramidHeight; rowNumber++) {
if (inverted) {
rows.unshift(generatePyramidRow(rowNumber, pyramidHeight));
} else {
rows.push(generatePyramidRow(rowNumber, pyramidHeight));
}
}
8
Notice the output of the cell, which is equal to the height of the pyramid. This is due to Jupyter’s behavior of displaying the result of the last evaluated statement. It can be suppressed by adding a dummy line at the end, like void 0;
(which produces undefined
).
[
' # ',
' ### ',
' ##### ',
' ####### ',
' ######### ',
' ########### ',
' ############# ',
' ############### ',
' ################# ',
'###################'
]
#
###
#####
#######
#########
###########
#############
###############
The code still looks somewhat unfamiliar compared to what I’m used to in Python. Here are some noteworthy points:
SPEED_OF_LIGHT = 299792458
). In JavaScript, however, a constant truly is a constant, and the language enforces that it cannot be changed (const speedOfLight = 299792458;
).const
for arrays and objects is considered a good practice in JavaScript because it prevents the variable from being accidentally reassigned. const
ensures the variable refers to the same instance, but you can still modify the instance’s contents.${whitespace}${pyramid}${whitespace}
is a template literal, which is the JavaScript equivalent of a Python f-string. Template literals are enclosed in backticks (`) and allow you to inject dynamic content using ${name}
.My first few days with JavaScript have been an interesting ride. As stated above, my approach is likely quite unusual, but I feel it’s effective for my personal learning journey. The familiar environment of Jupyter notebooks allows me to see results quickly without having to focus too much on setup or infrastructure. I’m certain, however, that future JavaScript projects will look different as I explore more traditional ways of working with the language.