7 любопытных фич JavaScript, которые уже устарели

Перевод статьи «7 interesting deprecated JavaScript features».

Photo by Tara Evans on Unsplash

Со времени появления на свет (26 лет назад, в Netscape) JavaScript прошел долгий путь. Язык, который использовался только для взаимодействия с Java-апплетами и выполнения простых DOM-манипуляций, теперь применяется для создания десктопных и мобильных приложений, причем и по части бэкенда.

Экосистема и сообщество JavaScript также очень сильно расширились.

Как и в любом другом языке, в JavaScript были (и все еще есть) шероховатости и странности. С некоторыми из них мы практически сроднились — из-за проблем обратной совместимости. Но некоторые, к счастью или несчастью, практически канули в лету. Часть этих устаревших фич, правда, все еще можно использовать, хотя это не поощряется.

Методы Object.prototype.watch и Object.prototype.unwatch

Когда-то у нас был простой способ просмотреть изменения свойства объекта.

var cat = {};
cat.watch("name", function (propertyName, previousValue, newValue) {
  return "Mr. " + newValue;
});

cat.name = "Oswald";
console.log("Hello " + cat.name + "!"); // Hello Mr. Oswald!

cat.unwatch("name");

cat.name = "Luna";
console.log("Hello " + cat.name + "!"); // Hello Luna!

Альтернативный вариант

Сегодня с той же целью мы можем использовать Proxy.

const handler = {
  set: (obj, prop, value) => {
    if (prop === 'name') {
      obj[prop] = `Mr. ${value}`;
    }
  }
};

let cat = new Proxy({}, handler);

cat.name = "Oswald";
console.log("Hello " + cat.name + "!"); // Hello Mr. Oswald!

cat = { ..cat }; // this will remove behavior imposed by Proxy

cat.name = "Luna";
console.log("Hello " + cat.name + "!"); // Hello Luna!

Оператор with

Все мы знаем, насколько ужасной может быть работа с длинными цепочками свойств. К счастью, есть способ это обойти. Но, к несчастью, этим способом пользоваться не следует.

const cat = {
  details: {
    passport: {
      location: {
        city: 'New York'
      }
    }
  }
};

with (cat.details.passport.location) {
  city = 'Meowyork';
}

Есть две причины, по которым не стоит использовать оператор with:

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

Кроме того, использовать оператор with в ES6+ невозможно. То же касается и ES5 с включенным строгим режимом.

Альтернативный вариант

Лучшее, что можно сделать, это объявить переменную, которая будет содержать цепочку свойств.

const cat = {
  details: {
    passport: {
      location: {
        city: 'New York'
      }
    }
  }
};

const catLocation = cat.details.passport.location;
catLocation.city = 'Meowyork';

Expression closures (затворы выражения)

Когда стрелочных функций еще и в планах не было, у нас были expression closures. Они позволяли пропускать фигурные скобки и операторы return из определений методов.

var cat = function() "Luna";

var favorites = {
  food: function() "Tuna"
};

Альтернативный вариант

Мы отказались от этого в пользу стандартного ES-синтаксиса.

var cat = function() { return "Luna"; }

var favorites = {
  food: function() { return "Tuna"; }
};

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

const cat = () => "Luna";

const favorites = {
  get food() { return "Tuna"; }
};

Методы Object.observe и Object.unobserve

Раньше у нас также был простой способ получить информацию о любых изменениях в объекте.

var cat = {
  name: "Oswald"
};

Object.observe(cat, function(changes) {
  console.log(changes);
});

cat.name = "Luna";
// [{ name: 'name', object: <obj>, type: 'update', oldValue: 'Oswald' }]

Object.unobserve(cat);

cat.name = "Max";

Были еще похожие методы для массивов — Array.observe и Array.unobserve.

Альтернативный вариант

Это тоже можно сделать при помощи Proxy.

const cat = new Proxy({ name: "Oswald" }, {
  get: (target, prop) => {
    console.log({ type: "get", target, prop });
    return Reflect.get(target, prop);
  },
  set: (target, prop, value) => {
    console.log({ type: "set", target, prop, value });
    return Reflect.set(target, prop, value);
  }
});

cat.name = "Luna";
// { type: 'set', target: <obj>, prop: 'name', value: 'Luna' }

cat.name;
// { type: 'get', target: <obj>, prop: 'name' }

let-выражения и let-блоки

В ES6 были представлены два оператора для объявления переменных с блочной областью видимости: let и const. На протяжении некоторого (короткого) времени существовали нестандартные расширения для оператора let. Это были let-выражения и let-блоки.

let-блоки позволяли создать блок, где переменные могли получать различные значения, что никак не влияло на переменные с такими же именами за пределами этого блока.

var catName = "Oswald";
var catAge = 2.5;

let (catName = "Luna", catAge = 2) {
  console.log(catName + "(" + catAge + " years old)"); // Luna (2 years old)
}

console.log(catName + "(" + catAge + " years old)"); // Oswald (2.5 years old)

let-выражения работали аналогично, только на уровне выражений.

var catName = "Oswald";

let(catName = "Luna") console.log(catName); // Oswald

console.log(catName); // Luna

Альтернативный вариант

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

let catName = "Oswald";
let catAge = 2.5;

{
  let catName = "Luna", catAge = 2;
  console.log(catName + "(" + catAge + " years old)"); // Luna (2 years old)
}

console.log(catName + "(" + catAge + " years old)"); // Oswald (2.5 years old)

Методы для оборачивания строк в теги HTML

Это был целый набор методов, с помощью которых можно было заключить строки с теги типа bold, blink, font, small, big, i и т. д.

"Some teeny-tiny text".fontsize(3);    // <font size="3">Some teeny-tiny text.</font>
"Some tiny text.".small();             // <small>Some tiny text.</small>
"Some yuuuge text.".big();             // <big>Some yuuge text.</big>
"Talk to the hand!".bold();            // <b>Talk to the hand!</b>
"You have been terminated.".blink();   // <blink>You have been terminated.</blink>

Альтернативный вариант

Для этого ужаса альтернативных вариантов не сделали.

ParallelArray

Это была экспериментальная фича, представленная Mozilla в Firefox (конкретно — в 17 версии движка Gecko). Ее целью было обеспечить параллелизм данных за счет параллельного выполнения нескольких функций. Если одновременное выполнение было невозможно, функции выполнялись последовательно.

var cats = new ParallelArray(["Oswald", "Luna", "Max"]);
cats.map(function(name) {
  return "😸 " + cat;
});

Альтернативный вариант

Сегодня для этого используется Promise.all.

Итоги

Просто дух захватывает, когда видишь, как сильно изменился JavaScript за последние 26 лет. Могли ли мы подумать, что этот язык, написанный за 10 дней, станет одним из доминирующих в сфере разработки?

Я считаю, что иногда полезно сделать шаг назад и посмотреть, как те или иные вещи делались раньше. Это позволяет избежать повторения ошибок, а кроме того пробуждает чувство благодарности за то, что мы имеем сегодня.

И хотя я довольно критически отношусь к JavaScript, я очень хочу увидеть те изменения, которые в нем произойдут в следующие 20 лет.

[customscript]techrocks_custom_after_post_html[/customscript]

[customscript]techrocks_custom_script[/customscript]

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх