Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
LoginSign Up
menu
  1. Home
  2. /Web Development
  3. /Javascript
  4. /Javascript Best Practices
Your Progress0%
0 of 61 completed

JavaScript Topics

Getting Started

  • What is JavaScript?
  • JavaScript vs Other Languages
  • Setting Up Your JavaScript Environment
  • Developer Console and Debugging Basics

JavaScript Fundamentals

  • Variables (var, let, const)
  • Data Types and Type Checking
  • Comments and Code Organization
  • String Methods and Template Literals
  • Type Conversion and Coercion
  • Operators (Arithmetic, Comparison, Logical)

Control Flow

  • If/Else Statements
  • Switch Statements
  • Ternary Operator
  • Truthy and Falsy Values
  • Logical Operators and Short-Circuiting

Loops and Iteration

  • For Loops
  • While and Do-While Loops
  • For...of and For...in Loops
  • Break and Continue Statements

Functions

  • Function Declarations and Expressions
  • Arrow Functions
  • Function Parameters and Arguments
  • Return Statements and Values
  • Scope and Closures
  • Higher-Order Functions and Callbacks

Arrays

  • Array Basics and Creation
  • Array Methods: Adding and Removing Elements
  • Array Iteration Methods (forEach, map, filter)
  • Array Methods: find, some, every, reduce
  • Sorting, Reversing, and Array Transformation

Objects

  • Object Basics and Properties
  • Object Methods and 'this' Keyword
  • Object Destructuring
  • Object.keys, values, entries
  • Spread Operator and Object Cloning

DOM Manipulation

  • Introduction to the DOM
  • Selecting Elements (querySelector, getElementById)
  • Modifying Elements (textContent, innerHTML, style)
  • Creating and Removing Elements
  • Event Listeners and Event Handling
  • Event Object and Event Delegation

Asynchronous JavaScript

  • Understanding Asynchronous Code
  • setTimeout and setInterval
  • Callbacks and Callback Hell
  • Promises and Promise Chaining
  • Async/Await

Error Handling

  • Try, Catch, Finally
  • Throwing Custom Errors

Modern JavaScript Features

  • ES6+ Overview
  • Modules (import/export)
  • Optional Chaining and Nullish Coalescing
  • Rest and Spread Operators

Working with Data

  • JSON (Parse and Stringify)
  • Fetch API and HTTP Requests
  • Working with Local Storage

Advanced Concepts

  • Classes and Object-Oriented Programming
  • Array and Object Advanced Patterns
  • Regular Expressions Basics

Best Practices & Real-World Application

  • JavaScript Best Practices
  • Debugging Techniques and Tools
  • Building a Complete Interactive Project

JavaScript Best Practices

Writing clean, maintainable, professional code

Writing code that works is just the beginning. Writing code that's clean, maintainable, and professional separates good developers from great ones. Best practices aren't arbitrary rules—they're lessons learned from decades of software development. From naming conventions to error handling, from code organization to performance optimization, these principles help you write code that you and your team will be proud of. Let's master JavaScript best practices!

Clean Code Principles

Clean Code Characteristics:

  • Readable - easy to understand at a glance
  • Maintainable - easy to modify and extend
  • Simple - does one thing well
  • Testable - easy to verify correctness
  • Self-documenting - code explains itself
  • Consistent - follows predictable patterns

Naming Conventions

Descriptive names improve readability

Bad Naming

// Bad: Unclear names
let d = new Date();
let x = 10;
let arr = [];

function calc(a, b) {
  return a * b * 0.2;
}

// Cryptic abbreviations
let usrNm = 'Alice';
let tmpVal = getData();

// Inconsistent naming
let UserName = 'Bob';
let user_age = 25;
let USERTYPE = 'admin';
Output:
Not run yet...

Good Naming

// Good: Descriptive names
let currentDate = new Date();
let maxRetries = 10;
let users = [];

function calculateDiscount(price, quantity) {
  const DISCOUNT_RATE = 0.2;
  return price * quantity * DISCOUNT_RATE;
}

// Clear and full words
let username = 'Alice';
let temporaryValue = getData();

// Consistent camelCase
let userName = 'Bob';
let userAge = 25;
let userType = 'admin';
Output:
Not run yet...
JAVASCRIPT
// Naming Conventions

// Variables and functions: camelCase
let firstName = 'Alice';
let totalAmount = 100;
function calculateTotal() { }
function getUserData() { }

// Constants: UPPER_SNAKE_CASE
const MAX_USERS = 100;
const API_BASE_URL = 'https://api.example.com';
const DEFAULT_TIMEOUT = 5000;

// Classes: PascalCase
class User { }
class ShoppingCart { }
class ProductManager { }

// Private properties: prefix with underscore (convention)
class BankAccount {
  constructor() {
    this._balance = 0;  // Private
    this.accountNumber = '123';  // Public
  }
}

// Booleans: use is/has/should prefix
let isValid = true;
let hasPermission = false;
let shouldRetry = true;

// Arrays: plural nouns
let users = [];
let products = [];
let orders = [];

// Functions: verb + noun
function getUser() { }
function createOrder() { }
function validateEmail() { }
function calculateTotal() { }

// Event handlers: handle + Event
function handleClick() { }
function handleSubmit() { }
function handleKeyPress() { }

Variable Declarations

Use const/let, declare explicitly

Bad Variable Practices

// Bad: Using var
var count = 0;
var message = 'Hello';

// Bad: Missing declarations
function example() {
  result = 10;  // Implicit global!
}

// Bad: Declaring at bottom
function process() {
  doSomething();
  calculate();
  let x = 5;  // Declared late
}

// Bad: Multiple vars
var a = 1, b = 2, c = 3;
Output:
Not run yet...

Good Variable Practices

// Good: Use const by default
const MAX_ITEMS = 10;
const API_URL = 'https://api.com';

// Good: Use let for reassignment
let count = 0;
count++;

// Good: Always declare
function example() {
  let result = 10;  // Properly declared
}

// Good: Declare at top
function process() {
  let x = 5;  // Declared first
  doSomething();
  calculate();
}

// Good: One per line
const a = 1;
const b = 2;
const c = 3;
Output:
Not run yet...

Function Best Practices

Single responsibility, manageable parameters

Bad Function Design

// Bad: Long, multi-purpose function
function processUser(user) {
  // Validate
  if (!user.email || !user.email.includes('@')) {
    return false;
  }
  
  // Transform
  user.email = user.email.toLowerCase();
  user.name = user.name.trim();
  
  // Save to database
  db.save(user);
  
  // Send email
  sendEmail(user.email, 'Welcome!');
  
  // Log
  console.log('User processed:', user);
  
  // Update UI
  updateUI(user);
  
  return true;
}

// Too many parameters
function createUser(name, email, age, city, 
  country, phone, address, zip) {
  // ...
}
Output:
Not run yet...

Good Function Design

// Good: Single responsibility
function validateUser(user) {
  if (!user.email || !user.email.includes('@')) {
    throw new Error('Invalid email');
  }
}

function normalizeUser(user) {
  return {
    ...user,
    email: user.email.toLowerCase(),
    name: user.name.trim()
  };
}

function saveUser(user) {
  return db.save(user);
}

// Good: Options object for many params
function createUser(userData) {
  const {
    name,
    email,
    age,
    city,
    country,
    phone,
    address,
    zip
  } = userData;
  // ...
}
Output:
Not run yet...
JAVASCRIPT
// Function Best Practices

// 1. Do one thing well
// Bad
function updateUserAndSendEmail(user, message) {
  user.lastLogin = new Date();
  updateDatabase(user);
  sendEmail(user.email, message);
}

// Good
function updateUserLastLogin(user) {
  user.lastLogin = new Date();
  return updateDatabase(user);
}

function sendWelcomeEmail(user) {
  return sendEmail(user.email, 'Welcome!');
}

// 2. Return early
// Bad
function getDiscount(user) {
  let discount = 0;
  
  if (user) {
    if (user.isPremium) {
      if (user.orders > 10) {
        discount = 0.2;
      } else {
        discount = 0.1;
      }
    }
  }
  
  return discount;
}

// Good
function getDiscount(user) {
  if (!user) return 0;
  if (!user.isPremium) return 0;
  if (user.orders > 10) return 0.2;
  return 0.1;
}

// 3. Avoid side effects
// Bad - modifies input
function addTax(product) {
  product.price = product.price * 1.1;
  return product;
}

// Good - returns new object
function addTax(product) {
  return {
    ...product,
    price: product.price * 1.1
  };
}

// 4. Use default parameters
// Bad
function greet(name) {
  name = name || 'Guest';
  return `Hello, ${name}`;
}

// Good
function greet(name = 'Guest') {
  return `Hello, ${name}`;
}

// 5. Descriptive function names
// Bad
function proc(d) { }
function doIt() { }

// Good
function processPayment(order) { }
function validateUserInput() { }

Error Handling

Handle errors properly with context

Bad Error Handling

// Bad: Silent failures
function getUser(id) {
  try {
    return db.find(id);
  } catch (error) {
    // Swallowing error - bad!
  }
}

// Bad: Generic error messages
if (!user) {
  throw new Error('Error');
}

// Bad: Not handling errors
async function loadData() {
  let data = await fetch('/api/data');
  return data.json();
  // No error handling!
}
Output:
Not run yet...

Good Error Handling

// Good: Proper error handling
function getUser(id) {
  try {
    return db.find(id);
  } catch (error) {
    console.error('Failed to get user:', error);
    throw error;  // Re-throw
  }
}

// Good: Descriptive errors
if (!user) {
  throw new Error(`User not found: ID ${userId}`);
}

// Good: Try-catch with meaningful handling
async function loadData() {
  try {
    let response = await fetch('/api/data');
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    console.error('Failed to load data:', error);
    return null;  // Graceful fallback
  }
}
Output:
Not run yet...
JAVASCRIPT
// Error Handling Best Practices

// 1. Use try-catch for async operations
async function fetchUserData(userId) {
  try {
    let response = await fetch(`/api/users/${userId}`);
    
    if (!response.ok) {
      throw new Error(`Failed to fetch user: ${response.status}`);
    }
    
    return await response.json();
  } catch (error) {
    console.error('Error fetching user:', error);
    throw error;  // Let caller handle
  }
}

// 2. Create custom error types
class ValidationError extends Error {
  constructor(message, field) {
    super(message);
    this.name = 'ValidationError';
    this.field = field;
  }
}

function validateEmail(email) {
  if (!email.includes('@')) {
    throw new ValidationError('Invalid email format', 'email');
  }
}

// 3. Fail fast
function processOrder(order) {
  if (!order) {
    throw new Error('Order is required');
  }
  
  if (!order.items || order.items.length === 0) {
    throw new Error('Order must have items');
  }
  
  if (order.total <= 0) {
    throw new Error('Order total must be positive');
  }
  
  // Process order...
}

// 4. Provide context in errors
function divideNumbers(a, b) {
  if (b === 0) {
    throw new Error(`Cannot divide ${a} by zero`);
  }
  return a / b;
}

// 5. Handle specific error types
try {
  validateEmail(email);
  processPayment(order);
} catch (error) {
  if (error instanceof ValidationError) {
    showFieldError(error.field, error.message);
  } else if (error.message.includes('payment')) {
    showPaymentError(error.message);
  } else {
    showGenericError();
  }
}

Code Organization

JAVASCRIPT
// File Structure Example

// constants.js - Configuration and constants
export const API_BASE_URL = 'https://api.example.com';
export const MAX_RETRIES = 3;
export const TIMEOUT = 5000;

export const USER_ROLES = {
  ADMIN: 'admin',
  USER: 'user',
  GUEST: 'guest'
};

// utils.js - Utility functions
export function formatDate(date) {
  return date.toLocaleDateString();
}

export function debounce(func, delay) {
  let timeoutId;
  return function(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
}

// api.js - API calls
import { API_BASE_URL } from './constants.js';

export async function fetchUsers() {
  let response = await fetch(`${API_BASE_URL}/users`);
  return response.json();
}

export async function createUser(userData) {
  let response = await fetch(`${API_BASE_URL}/users`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(userData)
  });
  return response.json();
}

// User.js - User class
export class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }
  
  get displayName() {
    return this.name.split(' ')[0];
  }
}

// main.js - Main application logic
import { fetchUsers, createUser } from './api.js';
import { User } from './User.js';
import { formatDate } from './utils.js';

async function initializeApp() {
  let users = await fetchUsers();
  displayUsers(users);
}

initializeApp();

Comments and Documentation

Comment WHY, not WHAT

Bad Comments

// Bad: Obvious comments
// Increment i
i++;

// Loop through array
for (let i = 0; i < arr.length; i++) {
  // Do something
  doSomething(arr[i]);
}

// Bad: Commented-out code
// function oldFunction() {
//   // old implementation
// }

// Bad: Misleading comments
// Returns user object
function getUsers() {  // Actually returns array!
  return [...];
}
Output:
Not run yet...

Good Comments

// Good: Explain WHY, not WHAT
// Cache results to avoid repeated API calls
let cachedUsers = null;

// Good: Document complex logic
// Using binary search for O(log n) performance
// on sorted array of 10k+ items
function findUser(id) {
  // ...
}

// Good: JSDoc for functions
/**
 * Calculates discounted price
 * @param {number} price - Original price
 * @param {number} discount - Discount (0-1)
 * @returns {number} Final price
 */
function applyDiscount(price, discount) {
  return price * (1 - discount);
}
Output:
Not run yet...
JAVASCRIPT
// Documentation Best Practices

// 1. JSDoc for public APIs
/**
 * Fetches user data from the API
 * @param {string} userId - The user's unique identifier
 * @param {Object} options - Optional configuration
 * @param {boolean} options.includeOrders - Include order history
 * @param {number} options.timeout - Request timeout in ms
 * @returns {Promise<User>} User object with profile data
 * @throws {Error} If user not found or network error
 * @example
 * const user = await fetchUser('123', { includeOrders: true });
 */
async function fetchUser(userId, options = {}) {
  // Implementation...
}

// 2. Explain complex algorithms
function calculateShippingCost(weight, distance) {
  // Using tiered pricing model:
  // 0-10 lbs: $5 base + $0.50/mile
  // 10-50 lbs: $10 base + $0.75/mile
  // 50+ lbs: $20 base + $1.00/mile
  
  let baseRate, perMile;
  
  if (weight <= 10) {
    baseRate = 5;
    perMile = 0.50;
  } else if (weight <= 50) {
    baseRate = 10;
    perMile = 0.75;
  } else {
    baseRate = 20;
    perMile = 1.00;
  }
  
  return baseRate + (distance * perMile);
}

// 3. Document non-obvious decisions
function processPayment(order) {
  // Using exponential backoff for retries
  // because payment gateway is rate-limited
  // to 100 requests per minute
  const maxRetries = 3;
  let delay = 1000;
  
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await paymentGateway.charge(order);
    } catch (error) {
      await sleep(delay);
      delay *= 2;  // Exponential backoff
    }
  }
}

// 4. TODO comments with context
// TODO: Implement caching after user feedback
// Current approach makes 3 API calls per page load
// Caching could reduce to 1 call, but need to handle
// cache invalidation for real-time updates
function loadDashboard() {
  // ...
}

Performance Best Practices

JAVASCRIPT
// Performance Best Practices

// 1. Avoid unnecessary DOM queries
// Bad
for (let i = 0; i < items.length; i++) {
  document.getElementById('list').innerHTML += `<li>${items[i]}</li>`;
}

// Good - query once, build string
let list = document.getElementById('list');
let html = items.map(item => `<li>${item}</li>`).join('');
list.innerHTML = html;

// 2. Debounce expensive operations
function debounce(func, delay) {
  let timeoutId;
  return function(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
}

// Use for search input
let searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce(function(e) {
  performSearch(e.target.value);
}, 300));

// 3. Use event delegation
// Bad - many event listeners
document.querySelectorAll('.item').forEach(item => {
  item.addEventListener('click', handleClick);
});

// Good - single listener on parent
document.getElementById('list').addEventListener('click', function(e) {
  if (e.target.classList.contains('item')) {
    handleClick(e);
  }
});

// 4. Cache computed values
// Bad - recalculates every time
function getExpensiveValue() {
  return items.reduce((sum, item) => {
    return sum + complexCalculation(item);
  }, 0);
}

// Good - cache result
let cachedValue = null;
function getExpensiveValue() {
  if (cachedValue === null) {
    cachedValue = items.reduce((sum, item) => {
      return sum + complexCalculation(item);
    }, 0);
  }
  return cachedValue;
}

// 5. Use appropriate data structures
// Bad - array for lookups
let users = [/* thousands of users */];
let user = users.find(u => u.id === targetId);  // O(n)

// Good - Map for fast lookups
let userMap = new Map(users.map(u => [u.id, u]));
let user = userMap.get(targetId);  // O(1)

// 6. Avoid memory leaks
// Bad - event listener not removed
function setupWidget() {
  let element = document.getElementById('widget');
  element.addEventListener('click', handleClick);
  // If widget removed, listener still exists!
}

// Good - clean up
function setupWidget() {
  let element = document.getElementById('widget');
  let handler = () => handleClick();
  element.addEventListener('click', handler);
  
  return function cleanup() {
    element.removeEventListener('click', handler);
  };
}

Security Best Practices

JAVASCRIPT
// Security Best Practices

// 1. Never trust user input
function createUserProfile(userData) {
  // Bad - directly using user input
  document.getElementById('name').innerHTML = userData.name;  // XSS risk!
  
  // Good - sanitize or use textContent
  document.getElementById('name').textContent = userData.name;
}

// 2. Validate on both client and server
function validateEmail(email) {
  // Client-side validation is for UX, not security
  let pattern = /^[\w.-]+@[\w.-]+\.[a-z]{2,}$/i;
  return pattern.test(email);
}

// Always validate on server too!
// app.post('/register', (req, res) => {
//   if (!validateEmail(req.body.email)) {
//     return res.status(400).send('Invalid email');
//   }
// });

// 3. Don't expose sensitive data
// Bad - API key in client code
const API_KEY = 'sk_live_12345';  // Exposed to everyone!
fetch(`https://api.com/data?key=${API_KEY}`);

// Good - API key on server
// Server-side code handles API key
// Client just calls your backend
fetch('/api/data');  // Your server adds the key

// 4. Use HTTPS for sensitive data
// Bad - sending password over HTTP
fetch('http://example.com/login', {
  method: 'POST',
  body: JSON.stringify({ password: 'secret' })
});

// Good - use HTTPS
fetch('https://example.com/login', {
  method: 'POST',
  body: JSON.stringify({ password: 'secret' })
});

// 5. Implement proper authentication
// Bad - storing password in localStorage
localStorage.setItem('password', userPassword);  // Never do this!

// Good - store only tokens, with expiration
function storeAuthToken(token, expiresIn) {
  let expiry = Date.now() + (expiresIn * 1000);
  sessionStorage.setItem('authToken', JSON.stringify({
    token,
    expiry
  }));
}

// 6. Prevent XSS
// Bad - eval with user input
eval(userInput);  // Extremely dangerous!

// Bad - innerHTML with user data
element.innerHTML = userComment;  // XSS risk

// Good - textContent or createElement
element.textContent = userComment;

// Or sanitize if HTML needed
function sanitizeHTML(html) {
  let temp = document.createElement('div');
  temp.textContent = html;
  return temp.innerHTML;
}

Code Quality Checklist

Before Committing Code:

  • ✓ Descriptive variable and function names
  • ✓ Functions are small and focused
  • ✓ No magic numbers (use named constants)
  • ✓ Proper error handling
  • ✓ Input validation
  • ✓ No console.logs in production
  • ✓ Consistent code formatting
  • ✓ Comments explain WHY, not WHAT
  • ✓ No unused variables or imports
  • ✓ Code is DRY (Don't Repeat Yourself)
  • ✓ Security considerations addressed
  • ✓ Performance considerations for loops/queries

Key Takeaways

  • Use descriptive names—code should be self-documenting
  • Use const by default, let when needed, never var
  • Functions should do one thing well
  • Handle errors properly with meaningful messages
  • Keep code DRY—don't repeat yourself
  • Comment WHY, not WHAT
  • Organize code into logical modules
  • Validate all user input
  • Consider performance for critical operations
  • Never trust client-side validation alone
  • Keep functions small (under 20-30 lines ideally)
  • Write code for humans first, computers second

What's Next?

You now understand JavaScript best practices and can write clean, maintainable, professional code! You've learned naming conventions, code organization, error handling, performance optimization, and security considerations.

In the next lesson, we'll explore Debugging Techniques and Tools—learning to use browser DevTools, set breakpoints, and troubleshoot issues effectively!

💪 Practice Challenge:

Before moving on, try:

  1. Refactor old code following best practices
  2. Review naming conventions in your projects
  3. Add proper error handling to functions
  4. Organize code into logical modules
  5. Document complex functions with JSDoc

Test Your Understanding

Question 1 / 4

What makes code 'clean' and maintainable?

Score: 0 / 0

Mastering JavaScript best practices! ✨

Previous
Regular Expressions Basics
Next
Debugging Techniques and Tools

Continue Learning JavaScript

Join 2,000+ developers mastering JavaScript. New lessons weekly - 100% FREE.

You might also like

UI Components

Ready-made components for your projects

Developer Tools

Boost productivity with handy generators

HTML Game

Learn HTML concepts through interactive gameplay

Join Our Web Development Training Program

Master frontend & backend development with hands-on projects.

JavaScript Tutorials

0 of 61 completed

Your Progress0%

Topics

Getting Started

  • What is JavaScript?
  • JavaScript vs Other Languages
  • Setting Up Your JavaScript Environment
  • Developer Console and Debugging Basics

JavaScript Fundamentals

  • Variables (var, let, const)
  • Data Types and Type Checking
  • Comments and Code Organization
  • String Methods and Template Literals
  • Type Conversion and Coercion
  • Operators (Arithmetic, Comparison, Logical)

Control Flow

  • If/Else Statements
  • Switch Statements
  • Ternary Operator
  • Truthy and Falsy Values
  • Logical Operators and Short-Circuiting

Loops and Iteration

  • For Loops
  • While and Do-While Loops
  • For...of and For...in Loops
  • Break and Continue Statements

Functions

  • Function Declarations and Expressions
  • Arrow Functions
  • Function Parameters and Arguments
  • Return Statements and Values
  • Scope and Closures
  • Higher-Order Functions and Callbacks

Arrays

  • Array Basics and Creation
  • Array Methods: Adding and Removing Elements
  • Array Iteration Methods (forEach, map, filter)
  • Array Methods: find, some, every, reduce
  • Sorting, Reversing, and Array Transformation

Objects

  • Object Basics and Properties
  • Object Methods and 'this' Keyword
  • Object Destructuring
  • Object.keys, values, entries
  • Spread Operator and Object Cloning

DOM Manipulation

  • Introduction to the DOM
  • Selecting Elements (querySelector, getElementById)
  • Modifying Elements (textContent, innerHTML, style)
  • Creating and Removing Elements
  • Event Listeners and Event Handling
  • Event Object and Event Delegation

Asynchronous JavaScript

  • Understanding Asynchronous Code
  • setTimeout and setInterval
  • Callbacks and Callback Hell
  • Promises and Promise Chaining
  • Async/Await

Error Handling

  • Try, Catch, Finally
  • Throwing Custom Errors

Modern JavaScript Features

  • ES6+ Overview
  • Modules (import/export)
  • Optional Chaining and Nullish Coalescing
  • Rest and Spread Operators

Working with Data

  • JSON (Parse and Stringify)
  • Fetch API and HTTP Requests
  • Working with Local Storage

Advanced Concepts

  • Classes and Object-Oriented Programming
  • Array and Object Advanced Patterns
  • Regular Expressions Basics

Best Practices & Real-World Application

  • JavaScript Best Practices
  • Debugging Techniques and Tools
  • Building a Complete Interactive Project
Falytom logoFALYTOM

Learn technologies like HTML, CSS, JavaScript, React, NodeJS and more through interactive games, tutorials, components and free tools. Transform your businesses with AI chatbots, SEO-optimized websites, and professional development services.

© 2025 Tomilola Group
  • Facebook logo
  • Twitter logo
  • Instagram logo
  • LinkedIn logo
  • GitHub logo
  • YouTube logo