The only language that runs natively in every browser - the backbone of the modern web, and increasingly servers too (Node.js). Copy-paste examples plus live Run/Submit exercises, running instantly in your own browser.
console.log("Hello, world!");
let age = 25; // can be reassigned
age = 26;
const name = "Sam"; // cannot be reassigned
// avoid "var" - it has confusing scoping rules from old JS
let price = 9.99; // number (no separate int/float)
let name = "Mo"; // string
let isValid = true; // boolean
let nothing = null; // intentionally empty
let notSet; // undefined - declared but never assigned
console.log(typeof price); // "number"
JavaScript has only one number type - no separate int/float. That makes decimal math a little dangerous for anything involving money.
console.log(0.1 + 0.2); // 0.30000000000000004 - binary floating-point can't store 0.1 exactly
console.log(0.1 + 0.2 === 0.3); // false!
// industry-standard fix: do money math in CENTS (integers), convert to dollars at the very end
const priceCents = 1090 + 2095;
const dollars = Math.round(priceCents) / 100;
console.log(dollars.toFixed(2)); // "31.85"
const a = 'single quotes'; // preferred default
const b = "double, to avoid escaping";
const c = 'I\'m learning JS'; // \' escapes the quote inside
const qty = 3, total = 2095;
console.log(`Items (${qty}): $${(total / 100).toFixed(2)}`); // template literal, multi-line capable
console.log('2.95' + 20.95); // "2.9520.95" - string + number CONCATENATES, doesn't add!
+ between a string and a number coerces the number to text instead of doing math - when building a template literal with math inside, wrap the numeric expression in parentheses first (as in the example above) so it evaluates before becoming part of the string.console.log(5 === '5'); // false - === checks type AND value
console.log(5 == '5'); // true - == silently converts types first
// always use === / !== - never == / != - to avoid surprise type coercion
if (age >= 18 && hasId) { } // AND - both must be true
if (isVip || total > 100) { } // OR - at least one true, short-circuits
if (!isBanned) { } // NOT
false in a condition): false, 0, '', NaN, undefined, null. Everything else - including "0" and empty arrays/objects - is truthy.const label = age >= 18 ? 'Adult' : 'Minor'; // condition ? ifTrue : ifFalse
// "default" pattern - || falls through to a fallback when the left side is falsy
const currency = selectedCurrency || 'USD';
// "guard" pattern - short-circuits out before running the right-hand side
const isReady = data && data.length > 0;
let age = 20;
if (age >= 18) {
console.log("Adult");
} else if (age >= 13) {
console.log("Teen");
} else {
console.log("Child");
}
for (let i = 0; i < 5; i++) {
console.log(i);
}
let n = 3;
while (n > 0) {
console.log(n);
n--;
}
for (let i = 0; i < 10; i++) {
if (i === 5) break; // stop the loop entirely
if (i % 2 === 0) continue; // skip just this iteration
console.log(i); // prints 1, 3
}
while loop, using continue before the increment step runs is a classic way to accidentally create an infinite loop - make sure the counter still advances before skipping.let nums = [10, 20, 30];
console.log(nums[0]); // 10
nums.push(40); // add to the end
console.log(nums.length); // 4
for (const n of nums) { // for...of - loop over VALUES
console.log(n);
}
JavaScript's array methods are how most real code is written - favor these over manual loops.
const nums = [1, 2, 3, 4, 5];
const doubled = nums.map(n => n * 2); // [2,4,6,8,10] - transform each item
const evens = nums.filter(n => n % 2 === 0); // [2,4] - keep matching items
const total = nums.reduce((sum, n) => sum + n, 0); // 15 - combine into one value
const found = nums.find(n => n > 3); // 4 - first match
nums.forEach((value, index) => { // the preferred way to just LOOP (no return value)
console.log(`${index}: ${value}`);
});
const person = {
name: "Ada",
age: 30,
greet() {
console.log(`Hi, I'm ${this.name}`);
}
};
console.log(person.name); // Ada
person.greet(); // Hi, I'm Ada
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // 5
function calculateTax(cost, taxRate = 0.1) { // default parameter - used if the caller omits it
return cost * taxRate;
}
console.log(calculateTax(100)); // 10 - uses the default 0.1
myFn), not the result of calling it (myFn()) - a very common mistake with callbacks and timers.A shorter function syntax, extremely common in modern JS - especially with array methods.
const add = (a, b) => a + b;
console.log(add(2, 3)); // 5
const square = n => n * n; // one param -> parens optional
console.log(square(4)); // 16
A function "remembers" the variables from the scope it was created in, even after that outer function has already returned - this is a closure.
function makeCounter() {
let count = 0; // captured by the inner function below
return function() {
count++;
return count;
};
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2 - count kept its value between calls, private to this counter
makeCounter() creates a brand-new, independent count - closures are how you get private, per-instance state without needing a class.const id = setTimeout(() => {
console.log('Ran once, after 1 second');
}, 1000);
const intervalId = setInterval(() => {
console.log('Runs every second, forever');
}, 1000);
clearInterval(intervalId); // stop it - otherwise it never ends on its own
const name = "Sam", age = 25;
console.log(`${name} is ${age} years old`); // backticks + ${} - no more string concatenation
const person = { name: "Ada", age: 30 };
const { name, age } = person; // pull fields out into variables
console.log(name, age); // Ada 30
const [first, second] = [10, 20]; // works on arrays too
document is a built-in object that links your JS to the actual webpage, so you can read and change what's on screen.
const buttonEl = document.querySelector('.js-subscribe-button'); // CSS-style selector
buttonEl.innerHTML = 'Subscribed'; // replace what's inside an element (parses HTML)
const allButtons = document.querySelectorAll('button'); // every match, as a list
buttonEl.classList.add('is-subscribed'); // toggle a CSS class from JS
buttonEl.classList.remove('is-subscribed');
innerHTML parses its string as real HTML (tags and all); innerText sets plain text and also strips extra whitespace when you read it back - they're not interchangeable.addEventListener is the modern, preferred way to react to user actions - an element can have several listeners, and they can be removed later.
buttonEl.addEventListener('click', () => {
console.log('Button was clicked!');
});
document.body.addEventListener('keydown', (event) => {
if (event.key === 'r') {
console.log('You pressed R');
}
});
data-* HTML attributes (e.g. data-product-id="abc123"), readable in JS as element.dataset.productId - a clean way to attach an ID for an event handler to read back.JSON (JavaScript Object Notation) is a text format for data that any language can read - used constantly for sending/storing objects.
const product = { name: 'Shirt', price: 1999 };
const text = JSON.stringify(product); // '{"name":"Shirt","price":1999}' - object -> string
const back = JSON.parse(text); // string -> object again
console.log(back.name); // Shirt
Lets a page save small amounts of data in the browser that survives a page refresh - but it only stores strings, so objects need JSON.stringify/parse.
localStorage.setItem('score', JSON.stringify({ wins: 3, losses: 1 }));
const score = JSON.parse(localStorage.getItem('score')) || { wins: 0, losses: 0 };
console.log(score.wins); // 3
localStorage.removeItem('score');
Splitting code across files avoids naming collisions between separate <script> tags - each module explicitly declares what it shares.
// cart.js
export function addToCart(productId) { /* ... */ }
export const cart = [];
// main.js
import { addToCart, cart } from './cart.js';
addToCart('abc123');
import/export needs <script type="module" src="main.js"></script>, and generally needs to be served over a local dev server rather than opened directly as a file:// path.A class is a blueprint for creating many similar objects, bundling data and behavior together. extends/super let one class build on another.
class Product {
#internalNote; // # = truly private, only accessible inside this class
constructor(name, priceCents) {
this.name = name;
this.priceCents = priceCents;
}
getPrice() {
return (this.priceCents / 100).toFixed(2);
}
}
class Clothing extends Product { // inherits everything from Product
constructor(name, priceCents, size) {
super(name, priceCents); // must call the parent constructor first
this.size = size;
}
}
const shirt = new Clothing('T-Shirt', 1999, 'M');
console.log(shirt.getPrice()); // "19.99" - inherited method
console.log(shirt instanceof Product); // true
this refers to the object it was called on - but a plain (non-arrow) callback passed to something like forEach loses that binding. Arrow functions don't have their own this - they inherit it from where they were written, which is why they're the safe default for callbacks inside a class method.try {
const data = JSON.parse('not valid json');
} catch (error) {
console.log('Something went wrong: ' + error.message);
} finally {
console.log('This always runs');
}
function withdraw(balance, amount) {
if (amount > balance) throw new Error('Insufficient funds');
return balance - amount;
}
A Promise represents a value that isn't ready yet, but will "resolve" (succeed) or "reject" (fail) later - the fix for deeply nested callbacks.
const waitOneSecond = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Done waiting!');
}, 1000);
});
waitOneSecond
.then((result) => console.log(result)) // runs once resolve() fires
.catch((error) => console.log(error)); // runs if reject() fires instead
// Promise.all waits for several promises to finish before continuing
Promise.all([waitOneSecond, fetch('/api/data')]).then(results => { /* ... */ });
fetch() is the modern, Promise-based way to talk to a server. async/await is syntax sugar over Promises that reads like ordinary top-to-bottom code - the generally preferred style over raw .then() chains.
async function loadOrder(orderId) {
try {
const response = await fetch(`/orders/${orderId}`);
const order = await response.json();
console.log(order);
} catch (error) {
console.log('Unexpected error, please try again later.');
}
}
await only works inside a function marked async. Prefer async/await > raw Promises > nested callbacks - each step reads top-to-bottom instead of nesting deeper and deeper.Runs instantly in your own browser - no server round-trip, same as Python.
const nums = [4, 8, 15, 16, 23, 42];
const sum = nums.reduce((a, b) => a + b, 0);
console.log(sum);
function reverse(s) {
return s.split("").reverse().join("");
}
console.log(reverse("javascript"));
const age = 16;
const label = age >= 18 ? 'Adult' : 'Minor';
console.log(label);
function greet(name) {
const safeName = name || 'Guest';
console.log(`Hello, ${safeName}!`);
}
greet('Ada');
greet(); // undefined is falsy -> falls back to 'Guest'
const prices = [999, 1499, 2000]; // cents
let totalCents = 0;
prices.forEach((price) => {
totalCents += price;
});
console.log((totalCents / 100).toFixed(2));
function isPrime(n) {
if (n < 2) return false;
for (let i = 2; i * i <= n; i++) {
if (n % i === 0) return false;
}
return true;
}
const numbers = [7, 10, 13, 1, 2];
for (const num of numbers) {
console.log(num + ' is prime: ' + isPrime(num));
}
function isPalindrome(str) {
const clean = str.toLowerCase();
let reversed = '';
for (let i = clean.length - 1; i >= 0; i--) {
reversed += clean[i];
}
return clean === reversed;
}
console.log(isPalindrome('racecar'));
console.log(isPalindrome('hello'));
console.log(isPalindrome('Level'));
function isLeapYear(year) {
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
}
const years = [2000, 1900, 2024, 2023];
for (const year of years) {
console.log(year + ': ' + isLeapYear(year));
}
function digitSum(n) {
let sum = 0;
let num = n;
while (num > 0) {
sum += num % 10;
num = Math.floor(num / 10);
}
return sum;
}
console.log(digitSum(1234));
console.log(digitSum(555));
console.log(digitSum(9));
function countVowels(str) {
let count = 0;
for (const char of str) {
const c = char.toLowerCase();
if (c === 'a' || c === 'e' || c === 'i' || c === 'o' || c === 'u') {
count++;
}
}
return count;
}
console.log(countVowels('Hello World'));
console.log(countVowels('JavaScript'));
console.log(countVowels('xyz'));
function greet(name = 'Guest', greeting = 'Hello') {
return greeting + ', ' + name + '!';
}
console.log(greet());
console.log(greet('Ada'));
console.log(greet('Sam', 'Welcome'));
function celsiusToFahrenheit(c) {
return c * 9 / 5 + 32;
}
function celsiusToKelvin(c) {
return c + 273.15;
}
const temp = 25;
console.log(temp + 'C = ' + celsiusToFahrenheit(temp) + 'F');
console.log(temp + 'C = ' + celsiusToKelvin(temp) + 'K');
function letterGrade(score) {
return score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : score >= 60 ? 'D' : 'F';
}
const scores = [95, 82, 71, 60, 40];
for (const score of scores) {
console.log(score + ' -> ' + letterGrade(score));
}
function sanitize(value) {
return value ? value : 'N/A';
}
const inputs = ['Alice', '', 0, 42, null, undefined, 'Bob'];
for (const input of inputs) {
console.log(sanitize(input));
}
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
console.log(factorial(5));
console.log(factorial(0));
console.log(factorial(7));
const nums = [1, 2, 3, 4, 5, 6, 7, 8];
const result = nums.filter(n => n % 2 === 0).map(n => n * n);
console.log(result.join(","));
function makeCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counterA = makeCounter();
const counterB = makeCounter();
console.log(counterA(), counterA(), counterA()); // 1 2 3
console.log(counterB()); // 1 - totally independent
class Animal {
constructor(name) { this.name = name; }
speak() { return `${this.name} makes a sound.`; }
}
class Dog extends Animal {
speak() { return `${this.name} barks.`; } // overrides the parent method
}
const animals = [new Animal('Generic'), new Dog('Rex')];
animals.forEach(a => console.log(a.speak()));
const cart = [{ id: 'a1', qty: 2 }, { id: 'b2', qty: 1 }];
const saved = JSON.stringify(cart);
console.log(saved);
const restored = JSON.parse(saved);
console.log(restored[0].qty + restored[1].qty); // 3
function gcd(a, b) {
while (b !== 0) {
const temp = b;
b = a % b;
a = temp;
}
return a;
}
function lcm(a, b) {
return (a * b) / gcd(a, b);
}
console.log('GCD:', gcd(48, 18));
console.log('LCM:', lcm(4, 6));
function bubbleSort(original) {
const result = [];
for (const item of original) {
result.push(item);
}
for (let i = 0; i < result.length; i++) {
for (let j = 0; j < result.length - i - 1; j++) {
if (result[j] > result[j + 1]) {
const temp = result[j];
result[j] = result[j + 1];
result[j + 1] = temp;
}
}
}
return result;
}
const numbers = [5, 2, 9, 1, 5, 6];
console.log(bubbleSort(numbers));
function charFrequency(str) {
const freq = {};
for (const char of str) {
if (freq[char]) {
freq[char]++;
} else {
freq[char] = 1;
}
}
return freq;
}
console.log(charFrequency('banana'));
function isArmstrong(n) {
let power = 0;
let temp = n;
while (temp > 0) {
power++;
temp = Math.floor(temp / 10);
}
let sum = 0;
temp = n;
while (temp > 0) {
const digit = temp % 10;
sum += Math.pow(digit, power);
temp = Math.floor(temp / 10);
}
return sum === n;
}
const numbers = [153, 370, 9474, 123];
for (const num of numbers) {
console.log(num + ': ' + isArmstrong(num));
}
function setupServer({ host, port, timeout = 30 }) {
return host + ':' + port + ' (timeout: ' + timeout + 's)';
}
const config1 = { host: 'localhost', port: 8080 };
const config2 = { host: '192.168.1.1', port: 443, timeout: 60 };
console.log(setupServer(config1));
console.log(setupServer(config2));
const products = [
{ name: 'Laptop', price: 1000, inStock: true },
{ name: 'Mouse', price: 25, inStock: true },
{ name: 'Monitor', price: 300, inStock: false },
{ name: 'Keyboard', price: 75, inStock: true }
];
const total = products
.filter((p) => p.inStock)
.map((p) => p.price * 1.1)
.reduce((sum, price) => sum + price, 0);
console.log(total.toFixed(2));
function createAccount(initialBalance) {
let balance = initialBalance;
return {
deposit: function(amount) {
balance += amount;
return balance;
},
withdraw: function(amount) {
if (amount > balance) {
return 'Insufficient funds';
}
balance -= amount;
return balance;
},
getBalance: function() {
return balance;
}
};
}
const account = createAccount(100);
console.log(account.deposit(50));
console.log(account.withdraw(30));
console.log(account.withdraw(1000));
console.log(account.getBalance());
class Circle {
constructor(radius) {
this.radius = radius;
}
getArea() {
return Math.PI * this.radius * this.radius;
}
getCircumference() {
return 2 * Math.PI * this.radius;
}
}
const circle = new Circle(5);
console.log(circle.getArea().toFixed(2));
console.log(circle.getCircumference().toFixed(2));
function createStack() {
const items = [];
return {
push: function(item) {
items.push(item);
},
pop: function() {
return items.pop();
},
peek: function() {
return items[items.length - 1];
},
size: function() {
return items.length;
}
};
}
const stack = createStack();
stack.push(10);
stack.push(20);
stack.push(30);
console.log(stack.peek());
console.log(stack.pop());
console.log(stack.size());
function sortString(str) {
const chars = [];
for (const c of str.toLowerCase()) {
chars.push(c);
}
for (let i = 0; i < chars.length; i++) {
for (let j = 0; j < chars.length - i - 1; j++) {
if (chars[j] > chars[j + 1]) {
const temp = chars[j];
chars[j] = chars[j + 1];
chars[j + 1] = temp;
}
}
}
let result = '';
for (const c of chars) {
result += c;
}
return result;
}
function isAnagram(a, b) {
return sortString(a) === sortString(b);
}
console.log(isAnagram('listen', 'silent'));
console.log(isAnagram('hello', 'world'));
console.log(isAnagram('Elvis', 'Lives'));
function reverseNumber(n) {
let num = n;
let reversed = 0;
while (num > 0) {
const digit = num % 10;
reversed = reversed * 10 + digit;
num = Math.floor(num / 10);
}
return reversed;
}
console.log(reverseNumber(12345));
console.log(reverseNumber(100));
console.log(reverseNumber(7));
function wordCount(text) {
const counts = {};
for (const word of text.split(" ")) {
counts[word] = (counts[word] || 0) + 1;
}
return counts;
}
const result = wordCount("the cat sat on the mat the cat ran");
for (const word in result) {
console.log(`${word}: ${result[word]}`);
}
function fetchUser(id) {
return new Promise((resolve) => {
resolve({ id: id, name: 'Ada' });
});
}
function fetchOrders(user) {
return new Promise((resolve) => {
resolve(['order1', 'order2']);
});
}
fetchUser(1)
.then((user) => fetchOrders(user)) // returning a promise from .then() chains flatly instead of nesting
.then((orders) => console.log(orders.length))
.catch((error) => console.log('Failed: ' + error));
function fetchPrice(itemId) {
return new Promise((resolve, reject) => {
if (itemId < 0) reject(new Error('Invalid item id'));
else resolve(1999);
});
}
async function printTotal(itemId) {
try {
const priceCents = await fetchPrice(itemId);
console.log((priceCents / 100).toFixed(2));
} catch (error) {
console.log('Error: ' + error.message);
}
}
printTotal(1);
printTotal(-1);
function isPerfectNumber(n) {
let sum = 0;
for (let i = 1; i < n; i++) {
if (n % i === 0) {
sum += i;
}
}
return sum === n;
}
const numbers = [6, 28, 12, 496];
for (const num of numbers) {
console.log(num + ' is perfect: ' + isPerfectNumber(num));
}
Builds Pascal's triangle using nested loops and prior-row lookups.
function pascalsTriangle(rows) {
const triangle = [];
for (let i = 0; i < rows; i++) {
const row = [];
for (let j = 0; j <= i; j++) {
if (j === 0 || j === i) {
row.push(1);
} else {
row.push(triangle[i - 1][j - 1] + triangle[i - 1][j]);
}
}
triangle.push(row);
}
return triangle;
}
const result = pascalsTriangle(5);
for (const row of result) {
let line = '';
for (const num of row) {
line += num + ' ';
}
console.log(line.trim());
}
function binarySearch(arr, target) {
let low = 0;
let high = arr.length - 1;
while (low <= high) {
const mid = Math.floor((low + high) / 2);
if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1;
}
const sorted = [2, 5, 8, 12, 16, 23, 38, 45, 56, 72];
console.log(binarySearch(sorted, 23));
console.log(binarySearch(sorted, 2));
console.log(binarySearch(sorted, 100));
A closure captures a cache object so repeated calls reuse previously computed Fibonacci values.
function createFibonacci() {
const cache = {};
function fib(n) {
if (cache[n] !== undefined) {
return cache[n];
}
if (n <= 1) {
return n;
}
const result = fib(n - 1) + fib(n - 2);
cache[n] = result;
return result;
}
return fib;
}
const fibonacci = createFibonacci();
console.log(fibonacci(10));
console.log(fibonacci(15));
console.log(fibonacci(1));
class Shape {
constructor(name) {
this.name = name;
}
area() {
return 0;
}
describe() {
return this.name + ' area: ' + this.area().toFixed(2);
}
}
class Circle extends Shape {
constructor(radius) {
super('Circle');
this.radius = radius;
}
area() {
return Math.PI * this.radius * this.radius;
}
}
class Square extends Shape {
constructor(side) {
super('Square');
this.side = side;
}
area() {
return this.side * this.side;
}
}
const shapes = [new Circle(3), new Square(4)];
for (const shape of shapes) {
console.log(shape.describe());
}
function saveCart(cart) {
return JSON.stringify(cart);
}
function loadCart(json) {
return JSON.parse(json);
}
const cart = {
items: [
{ name: 'Shirt', price: 20, qty: 2 },
{ name: 'Shoes', price: 60, qty: 1 }
],
coupon: null
};
const saved = saveCart(cart);
console.log(saved);
const loaded = loadCart(saved);
let total = 0;
for (const item of loaded.items) {
total += item.price * item.qty;
}
console.log('Total: ' + total);
console.log(loaded.coupon === null);
function formatReceipt(items) {
let receipt = `--- Receipt ---\n`;
let total = 0;
for (const item of items) {
const lineTotal = item.price * item.qty;
total += lineTotal;
receipt += `${item.name} x${item.qty}: $${lineTotal.toFixed(2)}\n`;
}
receipt += `Total: $${total.toFixed(2)}`;
return receipt;
}
const items = [
{ name: 'Coffee', price: 3.5, qty: 2 },
{ name: 'Bagel', price: 2.25, qty: 1 }
];
console.log(formatReceipt(items));
A custom Error subclass carries a descriptive message through throw/catch.
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = 'ValidationError';
}
}
function validateAge(age) {
if (typeof age !== 'number') {
throw new ValidationError('Age must be a number');
}
if (age < 0 || age > 120) {
throw new ValidationError('Age must be between 0 and 120');
}
return true;
}
const inputs = [25, -5, 'thirty', 150];
for (const input of inputs) {
try {
validateAge(input);
console.log(input + ' is valid');
} catch (error) {
console.log(input + ' error: ' + error.message);
}
}
function getUser() {
return new Promise((resolve) => {
resolve({ id: 1, name: 'Ada' });
});
}
function getOrders() {
return new Promise((resolve) => {
resolve([{ id: 101, total: 50 }, { id: 102, total: 75 }]);
});
}
Promise.all([getUser(), getOrders()]).then(([user, orders]) => {
console.log(user.name + ' has ' + orders.length + ' orders');
let total = 0;
for (const order of orders) {
total += order.total;
}
console.log('Total spent: ' + total);
});
runPipeline is awaited fully before the next call starts, so output stays strictly sequential.
function fetchStep1() {
return new Promise((resolve) => {
resolve('Step 1 complete');
});
}
function fetchStep2(shouldFail) {
return new Promise((resolve, reject) => {
if (shouldFail) {
reject(new Error('Step 2 failed'));
} else {
resolve('Step 2 complete');
}
});
}
async function runPipeline(shouldFail) {
try {
const result1 = await fetchStep1();
console.log(result1);
const result2 = await fetchStep2(shouldFail);
console.log(result2);
console.log('Pipeline finished');
} catch (error) {
console.log('Pipeline error: ' + error.message);
}
}
async function main() {
await runPipeline(false);
await runPipeline(true);
}
main();
function classifyTriangle(a, b, c) {
if (a + b <= c || a + c <= b || b + c <= a) {
return 'Not a valid triangle';
}
if (a === b && b === c) {
return 'Equilateral';
}
if (a === b || b === c || a === c) {
return 'Isosceles';
}
return 'Scalene';
}
console.log(classifyTriangle(3, 3, 3));
console.log(classifyTriangle(3, 3, 5));
console.log(classifyTriangle(3, 4, 5));
console.log(classifyTriangle(1, 1, 10));
class Book {
constructor(title, author, available) {
this.title = title;
this.author = author;
this.available = available;
}
describe() {
return `${this.title} by ${this.author}`;
}
}
const library = [
new Book('1984', 'George Orwell', true),
new Book('Dune', 'Frank Herbert', false),
new Book('Foundation', 'Isaac Asimov', true),
new Book('Brave New World', 'Aldous Huxley', false)
];
const availableBooks = library.filter((book) => book.available);
console.log('Available books: ' + availableBooks.length);
for (const book of availableBooks) {
console.log(book.describe());
}