Перевод статьи «7 interesting deprecated JavaScript features».
Со времени появления на свет (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]