25. JS с нуля, ваще с нуля (создаём клоны, фабрика)

Оценить качество материала и подачу материала автором видео:

Front-end

Трудоустройтесь middle front-end разработчиком на React JS (TypeScript) за 12-16 месяцев обучения с ежедневной менторской поддержкой в формате видео 1 на 1 и коммерческими проектами в портфолио

Перейти на курс
Front-end

Back-end

Трудоустройтесь middle back-end разработчиком за 12-16 месяцев обучения с ежедневной менторской поддержкой в формате видео 1 на 1 и коммерческими проектами в портфолио

Перейти на курс
Back-end

Карьерный бустер

Получите коммерческий опыт на реальных стартапах, прокачайте tech & soft навыки, научитесь работать в команде, проходить собеседования и получите первую работу в IT!

Перейти на курс
Карьерный бустер

Основы Front-end

Сделайте первый шаг в IT, освоив базовые знания разработки и научившись создавать небольшие проекты на JavaScript

Перейти на курс
Основы Front-end

Основы Back-end

Сделайте первый шаг в IT, освоив базовые знания разработки. Без опыта. Без математики. Только практика: JavaScript, SQL, Node JS, база данных

Перейти на курс
Основы Back-end

Создаём клоны, фабрика

Автор конспекта: Андрей Комаров

Фундаментальные концепции объектов

Что такое объект?

Объект в JavaScript — это контейнер для хранения данных и функциональности. Представьте его как коробку, где вы храните связанные вещи вместе.

Простая аналогия: если переменная — это один ящик для хранения, то объект — это целый комод с несколькими ящиками, каждый со своей меткой.

javascript
// Создаем простой объект, представляющий книгу
const book = {
  title: "JavaScript для начинающих",
  author: "Иван Иванов",
  year: 2023,
 
  // Метод (функция внутри объекта)
  getInfo: function () {
    return `${this.title}, автор: ${this.author}, ${this.year} год`
  },
}
 
console.log(book.getInfo()) // "JavaScript для начинающих, автор: Иван Иванов, 2023 год"

Создание объектов с помощью литерала

Самый простой способ создать объект — использовать литерал объекта {}:

javascript
// Создание пустого объекта
const emptyObject = {}
 
// Создание объекта со свойствами
const person = {
  name: "Анна",
  age: 25,
  city: "Москва",
}
 
// Каждый новый литерал {} создает уникальный объект в памяти
const person2 = {
  name: "Анна",
  age: 25,
  city: "Москва",
}
 
console.log(person === person2) // false - это разные объекты!

Контекст вызова this

Ключевое слово this ссылается на объект, в контексте которого выполняется функция.

javascript
const user = {
  name: "Мария",
  greet: function () {
    console.log("Привет, меня зовут " + this.name)
  },
}
 
user.greet() // "Привет, меня зовут Мария"
 
// Проблема: потеря контекста
const greetFunction = user.greet
greetFunction() // "Привет, меня зовут undefined" - this больше не ссылается на user
 
// Решение: привязка контекста
const boundGreet = user.greet.bind(user)
boundGreet() // "Привет, меня зовут Мария"

Клонирование объектов и проблема дублирования кода

Необходимость клонирования

Часто нужно создавать несколько однотипных объектов:

javascript
// Плохой подход - дублирование кода
const slider1 = {
  currentImage: 0,
  images: ["img1.jpg", "img2.jpg", "img3.jpg"],
  next: function () {
    this.currentImage = (this.currentImage + 1) % this.images.length
    console.log("Показываем: " + this.images[this.currentImage])
  },
}
 
const slider2 = {
  currentImage: 0,
  images: ["photo1.jpg", "photo2.jpg", "photo3.jpg"],
  next: function () {
    this.currentImage = (this.currentImage + 1) % this.images.length
    console.log("Показываем: " + this.images[this.currentImage])
  },
}

Много одинакового кода — сложно поддерживать!

Решение через функцию-конструктор

javascript
// Лучший подход - функция для создания однотипных объектов
function createSlider(images) {
  return {
    currentImage: 0,
    images: images,
    next: function () {
      this.currentImage = (this.currentImage + 1) % this.images.length
      console.log("Показываем: " + this.images[this.currentImage])
    },
  }
}
 
// Создаем несколько слайдеров без дублирования кода
const slider1 = createSlider(["img1.jpg", "img2.jpg", "img3.jpg"])
const slider2 = createSlider(["photo1.jpg", "photo2.jpg", "photo3.jpg"])
 
slider1.next() // "Показываем: img2.jpg"
slider2.next() // "Показываем: photo2.jpg"

Инкапсуляция и уникальные идентификаторы

Проблемы с глобальным поиском элементов

Когда на странице несколько компонентов, прямой поиск по ID или классу может вызывать конфликты:

html
<!-- HTML -->
<div id="slider1">
  <img src="img1.jpg" />
  <button class="next-btn">Следующий</button>
</div>
 
<div id="slider2">
  <img src="photo1.jpg" />
  <button class="next-btn">Следующий</button>
</div>
javascript
// Проблемный код
function problemSlider() {
  // Этот код найдет первую же кнопку на странице!
  const nextButton = document.querySelector(".next-btn")
  nextButton.addEventListener("click", function () {
    // Обработчик для переключения слайдов
  })
}

Решение через ограничение области поиска

javascript
// Правильный подход - поиск внутри конкретного контейнера
function createSlider(containerId) {
  const container = document.getElementById(containerId)
 
  // Ищем элементы только внутри контейнера
  const nextButton = container.querySelector(".next-btn")
  const image = container.querySelector("img")
 
  let currentImage = 0
  const images = ["img1.jpg", "img2.jpg", "img3.jpg"]
 
  nextButton.addEventListener("click", function () {
    currentImage = (currentImage + 1) % images.length
    image.src = images[currentImage]
  })
 
  return {
    // Можем вернуть методы для управления слайдером извне
    goNext: function () {
      currentImage = (currentImage + 1) % images.length
      image.src = images[currentImage]
    },
  }
}
 
// Создаем слайдеры для разных контейнеров
const slider1 = createSlider("slider1")
const slider2 = createSlider("slider2")

Рефакторинг и фабричные методы

Вынесение общего кода в функцию

javascript
// Улучшенная фабрика слайдеров
function createSlider(containerId, imageList) {
  const container = document.getElementById(containerId)
 
  // Создаем элементы слайдера
  const image = document.createElement("img")
  image.src = imageList[0]
 
  const nextButton = document.createElement("button")
  nextButton.textContent = "Следующий"
 
  container.appendChild(image)
  container.appendChild(nextButton)
 
  let currentImage = 0
 
  // Добавляем обработчик события
  nextButton.addEventListener("click", function () {
    currentImage = (currentImage + 1) % imageList.length
    image.src = imageList[currentImage]
  })
 
  // Возвращаем объект с методами для управления слайдером
  return {
    goNext: function () {
      currentImage = (currentImage + 1) % imageList.length
      image.src = imageList[currentImage]
    },
    goPrev: function () {
      currentImage = (currentImage - 1 + imageList.length) % imageList.length
      image.src = imageList[currentImage]
    },
    getCurrentImage: function () {
      return currentImage
    },
  }
}

Создание фабричного объекта

javascript
// sliderFactory - фабрика по производству слайдеров
const sliderFactory = {
  create: function (containerId, imageList) {
    const container = document.getElementById(containerId)
 
    // Создаем элементы интерфейса
    const image = document.createElement("img")
    image.src = imageList[0]
 
    const nextBtn = document.createElement("button")
    nextBtn.textContent = "Вперед"
 
    const prevBtn = document.createElement("button")
    prevBtn.textContent = "Назад"
 
    // Добавляем элементы в контейнер
    container.appendChild(prevBtn)
    container.appendChild(image)
    container.appendChild(nextBtn)
 
    let currentImage = 0
 
    // Обработчики событий
    nextBtn.addEventListener("click", () => {
      currentImage = (currentImage + 1) % imageList.length
      image.src = imageList[currentImage]
    })
 
    prevBtn.addEventListener("click", () => {
      currentImage = (currentImage - 1 + imageList.length) % imageList.length
      image.src = imageList[currentImage]
    })
 
    // Возвращаем объект слайдера с публичными методами
    return {
      next: function () {
        currentImage = (currentImage + 1) % imageList.length
        image.src = imageList[currentImage]
      },
      prev: function () {
        currentImage = (currentImage - 1 + imageList.length) % imageList.length
        image.src = imageList[currentImage]
      },
      getCurrent: function () {
        return currentImage
      },
      setCurrent: function (index) {
        if (index >= 0 && index < imageList.length) {
          currentImage = index
          image.src = imageList[currentImage]
        }
      },
    }
  },
}

Сравнение подходов к созданию объектов

ПодходПреимуществаНедостаткиКогда использовать
Литерал объекта {}Простота, наглядностьНевозможно повторное использованиеДля простых одноразовых объектов
Функция-конструкторУстранение дублирования кодаНет инкапсуляции, все свойства публичныеДля создания множества однотипных объектов
Фабричный методПолная инкапсуляция, гибкостьБольше кода, сложнее реализацияДля сложных компонентов с внутренним состоянием

Порядок подключения скриптов и отладка

Правильный порядок подключения

html
<!DOCTYPE html>
<html>
  <head>
    <title>Слайдеры</title>
  </head>
  <body>
    <div id="slider1"></div>
    <div id="slider2"></div>
 
    <!-- Сначала подключаем файл с фабрикой -->
    <script src="slider-factory.js"></script>
 
    <!-- Затем файл, который использует фабрику -->
    <script src="main.js"></script>
  </body>
</html>

Основы отладки кода

Для отладки используйте инструменты разработчика в браузере (F12):

  • Console — просмотр ошибок и вывод console.log()
  • Sources — установка точек останова (breakpoints)
  • Debugger — использование ключевого слова debugger; в коде
javascript
function createSlider(containerId, imageList) {
  debugger // Выполнение остановится здесь
  const container = document.getElementById(containerId)
  // остальной код...
}

🏠 Домашнее задание

Задание 1

Создайте фабрику для объекта "Пользователь" со следующими свойствами и методами

javascript
const userFactory = {
  create: function (name, email) {
    // Ваша реализация здесь
  },
}
 
// Пример использования:
const user1 = userFactory.create("Алексей", "alex@example.com")
const user2 = userFactory.create("Мария", "maria@example.com")
 
console.log(user1.getInfo()) // "Алексей (alex@example.com)"
console.log(user2.getInfo()) // "Мария (maria@example.com)"

Подсказка: объект пользователя должен иметь методы:

  • getInfo() — возвращает строку с именем и email
  • setEmail(newEmail) — изменяет email
  • getName() — возвращает имя

Задание 2

Создайте фабрику для создания объектов "Студент"

javascript
const studentFactory = {
  create: function (name, grade) {
    // Ваш код здесь
    return {
      // методы...
    }
  },
}
 
// Пример использования:
const student1 = studentFactory.create("Аня", 5)
const student2 = studentFactory.create("Петя", 4)
 
console.log(student1.getInfo()) // "Аня, 5 класс"
console.log(student2.getInfo()) // "Петя, 4 класс"

Подсказка: объект студента должен иметь методы:

  • getInfo() — возвращает строку с именем и классом
  • upgrade() — увеличивает класс на 1
  • changeName(newName) — изменяет имя

Заключение

Объекты — фундаментальная часть JavaScript. Понимание принципов их создания, клонирования и организации через фабричные методы поможет вам писать более чистый, поддерживаемый и масштабируемый код.

Помните главные принципы:

  • Избегайте дублирования кода
  • Инкапсулируйте логику внутри объектов
  • Используйте фабрики для создания однотипных объектов
  • Всегда проверяйте порядок подключения скриптов

Проверь себя

Вопрос 1: Почему в JavaScript так важен контекст ключевого слова this?

Ответ: this ссылается на объект, в контексте которого выполняется функция. Если this неправильно привязан, метод может пытаться получить доступ к свойствам несуществующего или неправильного объекта, что приведет к ошибкам.

Вопрос 2: Объясните, почему дублирование кода является "грехом номер один" в программировании.


Ответ: Дублирование кода создает проблемы с поддержкой и масштабированием. При необходимости внести изменения, их придется дублировать во всех местах, где есть одинаковый код, что увеличивает вероятность ошибок и затраты времени.

Вопрос 3: Что такое "фабричный метод" в контексте JavaScript-объектов?

Ответ: Фабричный метод — это функция или метод объекта, который отвечает за создание и возврат новых объектов. Он инкапсулирует логику создания, позволяя генерировать однотипные, но независимые экземпляры.

Боевой маршрут (JS Ваще с нуля)

Видеоурок - 26 видео из 29