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

  1. Автоматическая вставка точки с запятой
    Одной из самых известных особенностей JavaScript является автоматическая вставка точки с запятой. В отличие от большинства языков программирования, JavaScript не требует точки с запятой в конце каждого оператора. Если вы пропустите точку с запятой, JavaScript часто вставит ее вместо вас, что иногда может привести к неожиданному поведению.

Например:

function foo() {
  return
  {
    bar: 'hello'
  };
}

console.log(foo()); // undefined

В этом примере объектный литерал обрабатывается как отдельный оператор и не возвращается функцией, что приводит к выводу «undefined» вместо ожидаемого объекта.

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

console.log('5' + 5); // "55"
console.log('5' - 5); // 0

В этом примере первая строка объединяет две строки, а вторая строка вычитает 5 из строки «5», в результате чего получается число 0.

3. NaN
В JavaScript есть специальное значение, называемое NaN (не число), которое представляет собой результат неопределенной или непредставимой математической операции. Однако NaN не равно никакому значению, в том числе самому себе, что может сбивать с толку.

console.log(NaN === NaN); // false
console.log(NaN == NaN); // false

В этом примере оба сравнения возвращают false, даже если они сравнивают NaN с самим собой.

4. Правдивые и ложные значения
В JavaScript есть концепция истинных и ложных значений, то есть значений, которые рассматриваются как истинные или ложные в логических выражениях. Иногда это может привести к неожиданному поведению.

Например:

console.log(Boolean('')); // false
console.log(Boolean(0)); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false

В этом примере все значения считаются ложными, даже если они не являются явно ложными.

5. Глобальная область
В JavaScript переменные, объявленные вне функции, автоматически помещаются в глобальную область. Иногда это может привести к неожиданному поведению, особенно в больших приложениях.

Например:

var x = 10;

function foo() {
  var x = 5;
}

foo();

console.log(x); // 10

В этом примере переменная x внутри функции является локальной переменной и не влияет на глобальную переменную с тем же именем.

6. Подъем
В JavaScript есть концепция, называемая подъемом, которая означает, что объявления переменных и функций перемещаются в верхнюю часть соответствующих областей видимости. Иногда это может привести к неожиданному поведению, если вы не будете осторожны.

foo(); // "hello"

function foo() {
  console.log('hello');
}

В этом примере функция вызывается до ее объявления, но она все еще работает из-за подъема.

7. Динамические свойства объектов
JavaScript позволяет добавлять и удалять свойства объектов во время выполнения, что может быть полезно, но также может привести к неожиданному поведению.

Например:

var obj = {};

obj.foo = 'hello';
console.log(obj); // {foo: "hello"}

delete obj.foo;
console.log(obj); // {}

В этом примере мы добавляем свойство к объекту, а затем удаляем его, в результате чего получается пустой объект.

8. Наследование прототипов
JavaScript использует модель наследования на основе прототипов, которая отличается от классической модели наследования, используемой во многих других языках программирования. В этой модели объекты могут наследовать свойства и методы от других объектов, известных как их прототипы.

Например:

function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log('Animal speaking');
}

function Dog(name) {
  this.name = name;
}

Dog.prototype = new Animal();

Dog.prototype.bark = function() {
  console.log('Woof!');
}

var fido = new Dog('Fido');
fido.bark(); // "Woof!"
fido.speak(); // "Animal speaking"

В этом примере мы создаем функцию-конструктор Animal и добавляем метод к ее прототипу. Затем мы создаем функцию-конструктор Dog и устанавливаем ее прототип в экземпляр Animal, позволяя объектам Dog наследовать методы Animal. Наконец, мы создаем новый объект Dog и вызываем оба метода: bark и speak.

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

Например:

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

var multiply = function(a, b) {
  return a * b;
}

function calculator(operation, a, b) {
  return operation(a, b);
}

console.log(calculator(add, 2, 3)); // 5
console.log(calculator(multiply, 2, 3)); // 6

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

10. Асинхронное программирование
JavaScript — это однопоточный язык, но он также поддерживает асинхронное программирование с использованием обратных вызовов, промисов и async/await. Это позволяет коду JavaScript выполнять неблокирующие операции ввода-вывода и повышать производительность.

Например:

function fetchData(url) {
  return fetch(url)
    .then(function(response) {
      return response.text();
    });
}

fetchData('https://jsonplaceholder.typicode.com/posts/1')
  .then(function(response) {
    console.log(response);
});

В этом примере мы определяем функцию fetchData, которая использует метод fetch для извлечения данных из URL-адреса и возвращает обещание, которое разрешается текстом ответа. Затем мы вызываем функцию fetchData с URL-адресом и используем обещание, возвращенное fetchData, для записи ответа на консоль.

Обратите внимание, что метод fetch возвращает обещание, которое разрешается с помощью объекта Response, для которого мы затем вызываем метод text, чтобы получить текст ответа. Мы используем метод then для обработки промиса, возвращенного fetchData, и записываем текст ответа в консоль.

Заключение

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