☕ ТОП-5 вопросов и ответов по JavaScript на Stack Overflow за все время

Ответы на пять вопросов, ставящих в тупик каждого второго фронтендера.

Stack Overflow — платформа вопросов и ответов на любые темы по программированию. Вы задаете вопрос, а вам отвечает профессиональное сообщество программистов. Можно вопросы не задавать, а найти среди вопросов похожий на ваш. У вопросов и ответов на платформе формируется рейтинг, а ключевым в этом рейтинге является голосование. В статье рассмотрим пять лучших вопросов и ответов по JavaScript и его библиотеках.

1. Как удалить определенный элемент из массива?

Вопрос

Автор: Mateen Ulhaq

Как удалить конкретное значение из массива, а не все, как в этом примере:

array.remove(value);//удаляет все элементы со значением

Ответ

Автор: Kewal Shah

Найдите индекс элемента массива, который вы хотите удалить. Используйте indexOf, а затем удалите этот индекс с помощью splice.

Метод splice() изменяет содержимое массива, удаляя существующие элементы и добавляя новые элементы.

const array = [2, 5, 9];

console.log(array);

const index = array.indexOf(5);
if (index > -1) { // изменять только содержимое массива, когда элемент найден

  array.splice(index, 1); // 2-й параметр означает удаление только одного элемента
}

// array = [2, 9]
console.log(array);

Второй параметр splice — количество удаляемых элементов. Обратите внимание, что splice изменяет массив и возвращает новый массив, содержащий удаленные элементы.

Приведем пример функции. Функция removeItemOnce удаляет только одно вхождение. То есть удаляет первое совпадение 5 из [2,5,9,1,5,8,5]), а функция removeItemAll удаляет все вхождения:

function removeItemOnce(arr, value) {
  var index = arr.indexOf(value);
  if (index > -1) {
    arr.splice(index, 1);
  }
  return arr;
}

function removeItemAll(arr, value) {
  var i = 0;
  while (i < arr.length) {
    if (arr[i] === value) {
      arr.splice(i, 1);
    } else {
      ++i;
    }
  }
  return arr;
}
// использование
console.log(removeItemOnce([2,5,9,1,5,8,5], 5))
console.log(removeItemAll([2,5,9,1,5,8,5], 5))

В TypeScript эти функции могут оставаться безопасными с параметром типа:

function removeItem<T>(arr: Array<T>, value: T): Array<T> { 
  const index = arr.indexOf(value);
  if (index > -1) {
    arr.splice(index, 1);
  }
  return arr;
}
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека фронтендера»

2. Как проверить, скрыт ли элемент в jQuery?

Вопрос

Автор: Philip Morton

Как переключить видимость элемента в библиотеке jQuery с помощью .hide(), .show() или .toggle()? Как проверить, является ли элемент видимым или скрытым?

Ответ

Поскольку вопрос относится к одному элементу, этот код подойдет:

//Проверяет содержимое CSS для отображения: [none|block], игнорирует видимость: [true|false]
$(element).is(":visible");

// То же самое работает со скрытым
$(element).is(":hidden");

Мы используем is() jQuery для проверки выбранного элемента, селектора или объекта jQuery.

Этот метод проходит по элементам DOM и ищет совпадение с параметром. Если совпадение есть вернет true, если нет — false.

3. Для чего нужен use strict в JavaScript?

Вопрос

Автор: Mark Rogers

Недавно я пропустил часть своего кода JavaScript через Crockford JSLint, и он выдал следующую ошибку:

Problem at line 1 character 1: Missing "use strict" statement.

Я поискал решение и понял, что разработчики добавляют use strict в свой код. Как только я добавил этот параметр, ошибка перестала появляться. Думаю, что это имеет отношение к интерпретации JavaScript браузером.

Что такое use strict, что это означает, и актуально ли это на сегодняшний день? Понимают ли браузеры use strict?

Ответ

Автор: Pascal Martin

Внутри модулей ECMAScript с операторами импорта, экспорта и классов ES6 use strict всегда включен и не может быть отключен. Чтобы разобраться, можете почитать статью John Resig.

Приведем примеры некоторых интересных замечаний:

Строгий режим — это новая функция ECMAScript 5, которая позволяет поместить программу или функцию в «строгий» рабочий контекст. Этот строгий контекст предотвращает выполнение определенных действий и создает больше исключений.

Строгий режим помогает несколькими способами:

  • Он улавливает некоторые распространенные ошибки кодирования, вызывая исключения.
  • Он предотвращает или выдает ошибки при выполнении относительно «небезопасных» действий (например, при получении доступа к глобальному объекту).
  • Он отключает функции, которые сбивают с толку или плохо продуманы.

Также обратите внимание, что вы можете применить use strict ко всему файлу. Вы также можете использовать его для определенной функции:

Например:

// Нестрогий код

(function(){
//строгий код
  "use strict";

  // Define your library strictly...
})();

// нестрогий код

Это может быть полезно, если вам нужно смешивать старый и новый код. Usestrict поддерживается всеми основными браузерами.


4. Как перенаправить пользователя на другую веб-страницу?

Автор: venkatachalam

Ответ

Нельзя перенаправить пользователя с помощью jQuery.

Для этого jQuery не требуется. А window.location.replace(...) лучше всего имитирует перенаправление HTTP. Если вы хотите имитировать клик по ссылке, используйте location.href. Если вы хотите имитировать перенаправление HTTP, используйте location.replace.

Например:

//поведение, как перенаправление HTTP
window.location.replace("http://stackoverflow.com");

//поведение при переходе по ссылке
window.location.href = "http://stackoverflow.com";

window.location.replace(...) лучше, чем использование window.location.href, потому что replace() не сохраняет исходную страницу в истории сеанса, а это означает, что пользователь не застрянет в бесконечной обратной связи.

5. Как работают замыкания в JavaScript?

Вопрос

Автор: сообщество разработчиков

Как бы вы объяснили замыкания в JavaScript тому, кто знает принципы языка, но не понимает сами замыкания? Я видел пример схемы, приведенный в Википедии, но, к сожалению, это не помогло.

Ответ

Замыкание — это сочетание:

  • Функция и ссылка на внешнюю область действия этой функции (лексическое окружение).
  • Лексическое окружение является частью каждого контекста выполнения и представляет собой карту между именами локальных переменных и значениями.

Каждая функция в JavaScript поддерживает ссылку на свое внешнее окружение. Эта ссылка нужна для настройки контекста выполнения функции.

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

В следующем коде образуется замыкание с лексическим окружением контекста выполнения, созданного при вызове foo, закрывая переменную secret:

function foo() {
  const secret = Math.trunc(Math.random() * 100)
  return function inner() {
    console.log(`The secret number is ${secret}.`)
  }
}
const f = foo() // `secret` не доступен напрямую извне `foo`
f() // Единственный способ получить `secret`, состоит в том, чтобы вызвать `f`

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

Использование замыканий

Замыкания полезны, когда вам нужно приватное состояние, связанное с функцией. В JavaScript до 2015 года не было классов, и до сих пор нет синтаксиса частного поля.

Переменные частного экземпляра

В следующем коде функция toString закрывает детали автомобиля.

function Car(manufacturer, model, year, color) {
  return {
    toString() {
      return `${manufacturer} ${model} (${year}, ${color})`
    }
  }
}

const car = new Car('Aston Martin', 'V8 Vantage', '2012', 'Quantum Silver')
console.log(car.toString())

Функциональное программирование

В следующем коде внутренняя функция замыкается как для fn, так и для args.

function curry(fn) {
  const args = []
  return function inner(arg) {
    if(args.length === fn.length) return fn(...args)
    args.push(arg)
    return inner
  }
}

function add(a, b) {
  return a + b
}

const curriedAdd = curry(add)
console.log(curriedAdd(2)(3)()) // 5

Программирование, ориентированное на события

В следующем коде функция onClick закрывается по переменной BACKGROUND_COLOR.

const $ = document.querySelector.bind(document)
const BACKGROUND_COLOR = 'rgba(200, 200, 242, 1)'

function onClick() {
  $('body').style.background = BACKGROUND_COLOR
}

$('button').addEventListener('click', onClick)

<button>Set background color</button>

Модульность

В следующем примере все детали реализации скрыты внутри немедленно выполняемого функционального выражения.

Функции tick и toString закрываются по приватному состоянию и функциям, которые им необходимы для выполнения своей работы. Замыкания позволили нам модулизировать и инкапсулировать наш код.

let namespace = {};

(function foo(n) {
  let numbers = []

  function format(n) {
    return Math.trunc(n)
  }

  function tick() {
    numbers.push(Math.random() * 100)
  }

  function toString() {
    return numbers.map(format)
  }

  n.counter = {
    tick,
    toString
  }
}(namespace))

const counter = namespace.counter
counter.tick()
counter.tick()
console.log(counter.toString())

Примеры

Пример 1

Замыкание поддерживает ссылку на сами исходные переменные, как будто стек остается в памяти даже после выхода из внешней функции.

function foo() {
  let x = 42
  let inner = () => console.log(x)
  x = x + 1
  return inner
}

foo()() // logs 43

Пример 2

В этом коде три метода log, increment и update закрываются в одной и той же лексической среде. И каждый раз, когда вызывается createObject, создается новый контекст выполнения (фрейм стека) и создается новая переменная x и новый набор функций (журнал и т. д.), которые закрываются поверх этой новой переменной.

function createObject() {
  let x = 42;
  return {
    log() { console.log(x) },
    increment() { x++ },
    update(value) { x = value }
  }
}

const o = createObject()
o.increment()
o.log() // 43
o.update(5)
o.log() // 5
const p = createObject()
p.log() // 42

Пример 3

Если вы используете переменные, объявленные с помощью var, следите за тем, какую переменную вы закрываете. Переменные, объявленные с помощью var – поднимаются.

Это гораздо меньшая проблема в современном JavaScript из-за введения let и const. В следующем коде каждый раз вокруг цикла создается новая внутренняя функция, которая закрывается через i. Но поскольку var i поднимается за пределы цикла, все эти внутренние функции закрываются для одной и той же переменной, а это означает, что конечное значение i (3) печатается три раза.

function foo() {
  var result = []
  for (var i = 0; i < 3; i++) {
    result.push(function inner() { console.log(i) } )
  }

  return result
}

const result = foo()
// The following will print `3`, three times...
for (var i = 0; i < 3; i++) {
  result[i]() 
}

Заключительные пункты

  • Всякий раз, когда функция объявляется в JavaScript, создается закрытие.
  • Возврат функции из другой функции — классический пример замыкания, поскольку состояние внутри внешней функции неявно доступно для возвращаемой внутренней функции даже после того, как внешняя функция завершила выполнение.
  • Всякий раз, когда вы используете eval() внутри функции, используется замыкание. Текст, который вы оцениваете, может ссылаться на локальные переменные функции, а в нестрогом режиме вы даже можете создавать новые локальные переменные, используя eval('var foo = …').
  • Когда вы используете new Function(…) (конструктор Function) внутри функции, он не закрывается в своем лексическом окружении: вместо этого он закрывается в глобальном контексте. Новая функция не может ссылаться на локальные переменные внешней функции.
  • Замыкание в JavaScript похоже на сохранение ссылки на область видимости в точке объявления функции, которая, в свою очередь, сохраняет ссылку на свою внешнюю область видимости и так далее, вплоть до глобального объекта в верхней части цепочки масштабов.
  • Замыкание создается при объявлении функции; это закрытие используется для настройки контекста выполнения при вызове функции.
  • Каждый раз при вызове функции создается новый набор локальных переменных.
***

Мы рассмотрели 5 самых популярных вопросов на Stack Overflow:

1. Как удалить определенный элемент из массива?

2. Как проверить, скрыт ли элемент в JQuery?

3. Для чего нужен use strict в JavaScript?

4. Как перенаправить пользователя на другую веб-страницу?

5. Как работают замыкания в JavaScript?

Материалы по теме

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ