Howtojs

8 вещей, о которых я забыл в JavaScript

12 марта 2021 г. • ☕️ 5 мин.

С приходом ECMAScript 2015 (ES6), JavaScript стал развиваться очень стремительно, новые улучшения стали появляться каждый год. За счет большого количества новых фич, старые фичи/подходы часто остаются ненужными или используются в редких случаях.

Вспомним некоторые из них, которые были забыты, но когда-то использовались повсеместно.

Методы bind, call и apply

До появления стрелочных функций (arrow function), эти методы имели очень широкое применение. Хоть стрелочные функции не являются прямой заменой этим методам, они очень сильно перекрывают сценарии использования.

До

const user = {
  name: "John",
  sayHi: function() {
    console.log(`Hi, ${this.name}`)
  },
}

setTimeout(user.sayHi.bind(user), 1000)

После

const user = {
  name: "John",
  sayHi: function() {
    console.log(`Hi, ${this.name}`)
  },
}

setTimeout(() => user.sayHi(), 1000)

Явная работа с прототипами и наследование на функциях

В JavaScript ООП работает с помощью прототипов (prototype). Для реализации ООП и наследования приходилось использовать функции и явно работать с прототипами.

function User(name) {  this.name = name
}

User.prototype.sayHi = function() {
  console.log(this.name)
}

const user = new User("John")
user.sayHi()

Также многие библиотеки имели отдельные реализации упрощающие работу с “классами” и наследованием.

util - стандартная библиотека в Node.js

const util = require('util')
const EventEmitter = require('events')

function MyStream() {
  EventEmitter.call(this)
}

util.inherits(MyStream, EventEmitter)
MyStream.prototype.write = function(data) {
  this.emit('data', data)
}

const stream = new MyStream()

console.log(stream instanceof EventEmitter) // true
console.log(MyStream.super_ === EventEmitter) // true

React когда-то имел свою реализацию классов.

const createReactClass = require('create-react-class')

const Greeting = createReactClass({  render: function() {
    return <h1>Hello, {this.props.name}</h1>
  }
});

Новый синтаксис class добавил стандартную реализацию и абстрагировал многие детали.

class User {
  constructor(name) {
    this.name = name
  }
  sayHi() {
    console.log(this.name)
  }
}

var vs let и const

С появлением let и const использование var кануло в небытие, как и проблемы связанные с ним.

var

for (var i = 0; i < 10; i++) {  // ...
}

console.log(i) // 10

let

for (let i = 0; i < 10; i++) {  // ...
}

console.log(i) // ReferenceError: i is not defined

jQuery

Хоть это и не часть JavaScript, а библиотека, когда-то она имела огромную популярность, за счет того, что упрощала написание кода с удобным API. ES6 же принес много “синтаксического сахара”, после чего jQuery стал не нужен в большинстве ситуаций.

Пример jQuery

$(el).find(selector)

На чистом JavaScript

el.querySelectorAll(selector)

Существует даже веб-сайт, помогающий перейти с “синтаксиса” jQuery на JavaScript.

http://youmightnotneedjquery.com

Callbacks

Несмотря на то, что многие API браузера и Node.js до сих пор построены на callbacks, чаще всего для них пишут обертки с использованием Promise. Код, который мы пишем в программах, в основном использует Promise и async/await.

До

fs.readFile("./file.txt", (err, file) => {
  if (err) throw err
})

После

async function main() {
  const file = await fs.readFile("./file.txt")
}

Подробная статья про проблемы с callbacks

Код без модулей и проблемы с глобальными переменными

Раньше не было модулей, можно было только подключить файл через tag script, а так же использовать анонимные самовызывающиеся функции (IFFE) во избежание конфликтов названий глобальных переменных.

В скором это было решено использованием различнх менеджеров/сборщиков модулей, таких как webpack. А с приходом ESM появлась полноценная поддержка модульности в JavaScript.

import { hi } from './hi.js'
hi('John')

Псевдомассив arguments

Сейчас мы используем rest parameter синтаксис, позволяющий принять неопределенное количество аргументов, как массив.

function f(a, b, ...theArgs) {
  // ...
}

До его появления, для этих целей использовали псевдомассив arguments.

function f(a, b) {
  console.log(arguments)
}

Конкатенация строк

До появления шаблонных строк (Template Literals), очень часто использовалась простая конкатенация.

const name = "John"
const greeting = "Hello" + " " + name + "!"

В современном JavaScript для этих целей обычно используются шаблонные строки.

const name = "John"
const greeting = `Hello ${name}!`

Удобно, не правда ли?

Так с эволюцией языка, появляются новые абстракции, чтобы упростить решение типичных задач, а старые, остаются для сохранения обратной совместимости и решения узкого круга задач.