Introduction
As a Rails developer, you don’t need to be a JavaScript expert, but understanding key JavaScript concepts will help you write better Stimulus controllers and handle client-side interactions. This guide assumes you’re comfortable with Ruby but new to JavaScript.
JavaScript vs Ruby: Key Differences
Let’s start by comparing JavaScript with Ruby to understand the main differences:
Ruby | JavaScript |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Variables and Data Types
Declaring Variables
JavaScript has three ways to declare variables:
// let - can be reassigned
let name = "Ruby"
name = "JavaScript"
// const - cannot be reassigned
const pi = 3.14
// pi = 3.15 // This would cause an error
// var - old way, avoid using
var oldWay = "Don't use this"
Tip
|
Always use const by default. Use let only when you need to reassign a variable.
|
Common Data Types
// Strings
const name = "Ruby"
const greeting = 'Hello'
const template = `Hello, ${name}` // Template literals
// Numbers (no Integer/Float distinction)
const age = 25
const price = 19.99
// Booleans
const isActive = true
const hasErrors = false
// Arrays
const numbers = [1, 2, 3, 4, 5]
const names = ["Alice", "Bob", "Charlie"]
// Objects (similar to Ruby hashes)
const person = {
name: "John",
age: 30,
city: "Portland"
}
Functions
Functions in JavaScript are similar to Ruby methods:
// Traditional function
function greet(name) {
return `Hello, ${name}!`
}
// Arrow function (modern way)
const greet = (name) => {
return `Hello, ${name}!`
}
// Short arrow function (single line)
const greet = name => `Hello, ${name}!`
// Using functions
greet("Ruby") // => "Hello, Ruby!"
Function Parameters
// Default parameters (like Ruby)
const calculateTotal = (price, taxRate = 0.1) => {
return price + (price * taxRate)
}
// Object parameters (similar to Ruby keyword arguments)
const createUser = ({ name, email, age = null }) => {
console.log(`Creating user: ${name} (${email})`)
}
// Calling with object parameters
createUser({ name: "John", email: "john@example.com" })
Working with the DOM
The DOM (Document Object Model) is how JavaScript interacts with HTML:
// Finding elements
const element = document.querySelector(".my-class")
const elements = document.querySelectorAll(".my-class")
// Modifying elements
element.textContent = "New text"
element.innerHTML = "<strong>Bold text</strong>"
element.classList.add("active")
element.classList.remove("inactive")
element.classList.toggle("hidden")
// Creating elements
const div = document.createElement("div")
div.textContent = "New element"
document.body.appendChild(div)
Events
Events are how JavaScript handles user interactions:
// Adding event listeners
const button = document.querySelector("button")
button.addEventListener("click", (event) => {
console.log("Button clicked!")
event.preventDefault() // Like Rails' prevent_default
})
// Common events
// click - mouse clicks
// submit - form submissions
// input - text input changes
// change - form field changes
// keyup - keyboard key released
// keydown - keyboard key pressed
Modern JavaScript Features You’ll Use in Stimulus
Template Literals
// Ruby string interpolation: "Hello, #{name}!"
// JavaScript template literals:
const name = "Ruby"
const greeting = `Hello, ${name}!`
Object Destructuring
const person = { name: "John", age: 30 }
// Extract properties to variables
const { name, age } = person
// In function parameters
const greet = ({ name, age }) => {
console.log(`${name} is ${age} years old`)
}
Array Methods
const numbers = [1, 2, 3, 4, 5]
// map (like Ruby's map)
const doubled = numbers.map(num => num * 2)
// filter (like Ruby's select)
const evenNumbers = numbers.filter(num => num % 2 === 0)
// find (like Ruby's find)
const found = numbers.find(num => num > 3)
// some (like Ruby's any?)
const hasEven = numbers.some(num => num % 2 === 0)
Introduction to Stimulus
Now that you understand JavaScript basics, let’s look at a simple Stimulus controller:
// app/javascript/controllers/hello_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
// Define targets (like Ruby attr_accessor)
static targets = ["name", "output"]
// Define values that can be set in HTML
static values = {
greeting: String
}
// Called when controller connects to element
connect() {
console.log("Hello controller connected!")
}
// Action method
greet() {
const name = this.nameTarget.value
this.outputTarget.textContent =
`${this.greetingValue}, ${name}!`
}
}
Using the controller in HTML:
<div data-controller="hello" data-hello-greeting-value="Hello">
<input data-hello-target="name" type="text">
<button data-action="click->hello#greet">
Greet
</button>
<div data-hello-target="output"></div>
</div>
Debugging JavaScript
Console Methods
// Print to console
console.log("Basic logging")
console.warn("Warning message")
console.error("Error message")
// Inspect objects
const person = { name: "John", age: 30 }
console.log(person)
console.table(person) // Shows in table format
// Group related logs
console.group("Person Details")
console.log("Name:", person.name)
console.log("Age:", person.age)
console.groupEnd()
Using the Browser Developer Tools
-
Open Dev Tools (F12 or Right-click > Inspect)
-
Go to Console tab for JavaScript output
-
Go to Sources tab to set breakpoints
-
Use
debugger
statement in code to pause execution
Best Practices
JavaScript Style Guide
-
Use camelCase for variables and functions
-
Use const by default, let when needed
-
Use template literals for string interpolation
-
Keep functions small and focused
-
Use modern ES6+ features
Common Gotchas for Ruby Developers
// Equality comparison
// Ruby: == or .eql?
// JavaScript: === (strict equality)
1 === 1 // true
1 === "1" // false
1 == "1" // true (avoid using ==)
// Undefined vs Null
// Ruby: nil
// JavaScript: null and undefined
let value
console.log(value) // undefined
value = null // explicitly set to null
// This context
// Ruby: self
// JavaScript: this (depends on context)
class Example {
constructor() {
this.value = 42
}
// Arrow function preserves this
goodMethod = () => {
console.log(this.value) // 42
}
// Regular function changes this
badMethod() {
console.log(this.value) // undefined
}
}
Next Steps
Now that you understand JavaScript basics, you can:
-
Practice writing Stimulus controllers
-
Explore more JavaScript features
-
Learn about async/await for API calls
-
Dive into modern JavaScript frameworks
Additional Resources
Tip
|
Use your browser’s console (F12) to practice JavaScript as you learn. It’s like IRB for JavaScript! |
Warning
|
JavaScript runs in the browser, so always consider security implications and validate on the server side. |