Рубрики
Без рубрики

Что такое метапрограммирование в JavaScript? По английски пожалуйста.

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

Автор оригинала: FreeCodeCamp Community Member.

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

Метапрограммирование в JavaScript – это одна такая концепция, с которой многие из нас не могут быть знакомы. В этой статье мы узнаем о метапрограмме и как это полезно для нас.

С ES6 (Ecmascript 2015) у нас есть поддержка Отражать и Прокси Объекты, которые позволяют нам сделать метапрограммирование с легкостью. В этой статье мы узнаем, как их использовать с примерами.

MetaProgramming не что иное меньше, чем Магия в программировании ! Как насчет написания программы, которая читает, модифицирует, анализирует и даже генерирует программу? Разве это не звучит волшебным и мощным?

Wikipedia описывает метапрограммирование, как это:

Проще говоря, MetaProgramming включает в себя письменный код, который может

  • Генерировать код
  • Манипулировать языковыми конструкциями в течение времени выполнения. Это явление известно как Светоотражающее метапрограммирование или Отражение Отказ

Что такое отражение в метапрограмме?

Отражение это ветвь метапрограммирования. Отражение имеет три подразделения:

  1. Самоанализ : Код способен проверять себя. Он используется для доступа к внутренним свойствам, так что мы можем получить низкоуровневую информацию нашего кода.
  2. Самостоятельная модификация Как сообщает имя, код способен модифицировать себя.
  3. Собрание : Буквальный смысл заступника, действуя от имени кого-то еще. В MetaProgramming поступка делает точно так же, как и понятия, как, упаковочные, захватывающие, перехватывание.

ES6 дает нам Отражать объект (ака отражает API) для достижения Самоанализ Отказ Прокси Объект ES6 помогает нам с Собрание Отказ Мы не будем слишком много говорить о Самостоятельная модификация Как мы хотим держаться подальше от этого как можно больше.

Подожди секунду! Просто быть понятным, метапрограммирование не было введено в ES6. Скорее, это было доступно на языке от его создания. ES6 только что сделало его намного проще в использовании.

Предварительная ES6 ERA MetaProgramming

Вы помните Eval ? Давайте посмотрим, как это было использовано:

const blog = {
    name: 'freeCodeCamp'
}
console.log('Before eval:', blog);

const key = 'author';
const value = 'Tapas';
testEval = () => eval(`blog.${key} = '${value}'`);

// Call the function
testEval();

console.log('After eval magic:', blog);

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

Before eval: {name: freeCodeCamp}
After eval magic: {name: "freeCodeCamp", author: "Tapas"}

Самоанализ

До включения Отражать объект В ES6 мы все равно можем сделать самоанализ. Вот пример чтения структуры программы:

var users = {
    'Tom': 32,
    'Bill': 50,
    'Sam': 65
};

Object.keys(users).forEach(name => {
    const age = users[name];
    console.log(`User ${name} is ${age} years old!`);
});

Здесь мы читаем Пользователи Структура объекта и регистрация ключа-значения в предложении.

User Tom is 32 years old!
User Bill is 50 years old!
User Sam is 65 years old!

Самостоятельная модификация

Давайте возьмем объект блога, который имеет способ изменить себя:

var blog = {
    name: 'freeCodeCamp',
    modifySelf: function(key, value) {blog[key] = value}
}

Блог Объект может изменить себя, делая это:

blog.modifySelf('author', 'Tapas');

Заступничество

Собрание В MetaProgramming означает действовать или изменение вещей от имени кого-то или чего-то еще. Pre-ES6 Object.DefineProperty () Метод может изменить семантику объекта:

var sun = {};

Object.defineProperty(sun, 'rises', {
    value: true,
    configurable: false,
    writable: false,
    enumerable: false
});

console.log('sun rises', sun.rises);
sun.rises = false;
console.log('sun rises', sun.rises);

Выход:

sun rises true
sun rises true

Как вы можете видеть, Солнце Объект был создан как обычный объект. Затем семантика были изменены, так что это не пишется.

Теперь давайте прыгнем в понимание Отражать и Прокси объекты с их соответствующими использованиями.

В ES6 отражение – это новый Глобальный объект (Как и математика), что обеспечивает ряд полезных функций. Некоторые из этих функций могут сделать точно так же, как методы от Объект или Функция Отказ

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

Вот список доступных методов из Отражать объект.

// Reflect object methods

Reflect.apply()
Reflect.construct()
Reflect.get()
Reflect.has()
Reflect.ownKeys()
Reflect.set()
Reflect.setPrototypeOf()
Reflect.defineProperty()
Reflect.deleteProperty()
Reflect.getOwnPropertyDescriptor()
Reflect.getPrototypeOf()
Reflect.isExtensible()

Но подождите, вот вопрос: почему нам нужен новый объект API, когда они могут просто существовать уже или можно добавить в Объект или Функция ?

Смущенный? Давайте попробуем понять это.

Все в одном пространстве имен

JavaScript уже поддерживал отражение объекта. Но эти API не были организованы под одним пространством имен. С ES6 они сейчас под Отражать Отказ

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

Простым в использовании

самоанализ Методы Объект бросить исключение, когда они не могут завершить операцию. Это дополнительное бремя для потребителя (программиста) для обработки этого исключения в коде.

Вы можете предпочесть обрабатывать его как логический (правда | false) вместо того, чтобы использовать обработку исключений. Отрадный объект помогает вам сделать это.

Вот пример с объектом.defineProperty:

 try {
        Object.defineProperty(obj, name, desc);
    } catch (e) {
        // Handle the exception
    }

И с отражением API:

if (Reflect.defineProperty(obj, name, desc)) {
  // success
} else {
 // failure (and far better)
}

Впечатление функции первой классы

Мы можем найти существование свойства для объекта как (опоры в OBJ). Если нам нужно использовать его несколько раз в нашем коде, мы должны создать функцию, упаковывая этот код.

В ES6 API отражения решает эту проблему, введя первой классной функции, Refrect.has (Обжим, опоры) Отказ

Давайте посмотрим на другой пример: удалите свойство объекта.

const obj = { bar: true, baz: false};

// We define this function
function deleteProperty(object, key) {
    delete object[key];
}
deleteProperty(obj, 'bar');

С отражением API:

// With Reflect API
Reflect.deleteProperty(obj, 'bar');

Более надежный способ использования метода Apply ()

Применить () Метод в ES5 помогает вызвать функцию с контекстом это значение. Мы также можем пройти аргументы в качестве массива.

Function.prototype.apply.call(func, obj, arr);
// or
func.apply(obj, arr);

Это менее надежно, потому что Func может быть объектом, который бы определил бы свой собственный Применить метод.

В ES6 у нас есть более надежный и элегантный способ решения этого:

Reflect.apply(func, obj, arr);

В этом случае мы получим Типеррор Если Func не Callable.

Помощь другим видам отражения

Мы Увидим, что это значит немного, когда мы узнаем о Прокси объект. Методы API отражения могут быть использованы с прокси во многих случаях использования.

ES6’s Прокси Объект помогает в Собрание Отказ

Как указано имя, A прокси Объект помогает действовать от имени чего-либо. Это делает это путем виртуализации другого объекта. Виртуализация объекта обеспечивает пользовательское поведение для этого объекта.

Например, используя прокси-объект, мы можем виртуализировать поиск объекта объекта, вызов функции и т. Д. Мы увидим некоторые из них подробно ниже.

Вот несколько полезных терминов, которые вам нужно запомнить и использовать:

  • цель : Объект, который прокси дает пользовательское поведение.
  • обработчик : Это объект, который содержит ловушки.
  • ловушка : Ловушка – это метод, который обеспечивает доступ к свойствам целевого объекта. Это достигается с использованием методов отражения API. Каждая из методов ловушек сопоставлена методами от отражения API.

Вы можете представить это что-то вроде этого:

Обработчик с ловушка Функция должна быть определена. Затем нам нужно создать прокси-объект, используя обработчик и целевой объект. Прокси-объект будет иметь все изменения с применением пользовательского поведения.

Это совершенно хорошо, если вы еще не совсем понимаете из описания выше. Мы получим об этом через код и примеры в течение минуты.

Синтаксис для создания прокси-объекта выглядит следующим образом:

let proxy = new Proxy(target, handler);

Есть много прокси-ловушек (функций обработчика), доступных для доступа и настроить целевой объект. Вот список их.

handler.apply()
handler.construct()
handler.get()
handler.has()
handler.ownKeys()
handler.set()
handler.setPrototypeOf()
handler.getPrototypeOf()
handler.defineProperty()
handler.deleteProperty()
handler.getOwnPropertyDescriptor()
handler.preventExtensions()
handler.isExtensible()

Обратите внимание, что каждая из ловушек имеет сопоставление с Отражать Методы объекта. Это означает, что вы можете использовать Отражать и Прокси вместе во многих случаях использования.

Как получить недоступные значения объекта свойства

Давайте посмотрим на пример сотрудник Объект и попытаться распечатать некоторые его свойства:

const employee = {
    firstName: 'Tapas',
    lastName: 'Adhikary'
};

console.log(employee.firstName);
console.log(employee.lastName);
console.log(employee.org);
console.log(employee.fullName);

Ожидаемый выход следующий:

Tapas
Adhikary
undefined
undefined

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

Шаг 1: Создайте обработчик, который использует To Get Trap

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

let handler = {
    get: function(target, fieldName) {        

        if(fieldName === 'fullName' ) {
            return `${target.firstName} ${target.lastName}`;
        }

        return fieldName in target ?
            target[fieldName] :
                `No such property as, '${fieldName}'!`

    }
};

Вышеупомянутый обработчик помогает создать значение для Funnname имущество. Он также добавляет лучшее сообщение об ошибке при отсутствии свойства объекта.

Шаг 2: Создайте прокси-объект

Как у нас есть цель сотрудник Объект и обработчик, мы сможем создать прокси-объект, как это:

let proxy = new Proxy(employee, handler);

Шаг 3: Доступ к свойствам на прокси-объекте

Теперь мы можем получить доступ к свойствам объекта сотрудника с использованием прокси-объекта, как это:

console.log(proxy.firstName);
console.log(proxy.lastName);
console.log(proxy.org);
console.log(proxy.fullName);

Выход будет:

Tapas
Adhikary
No such property as, 'org'!
Tapas Adhikary

Обратите внимание, как мы волшебным образом изменили вещи для сотрудник объект!

Прокси для проверки значений

Давайте создадим прокси-объект для проверки целочисленного значения.

Шаг 1: Создайте обработчик, который использует набор ловушек

Обработчик выглядит так:

const validator = {
    set: function(obj, prop, value) {
        if (prop === 'age') {
            if(!Number.isInteger(value)) {
                throw new TypeError('Age is always an Integer, Please Correct it!');
            }
            if(value < 0) {
                throw new TypeError('This is insane, a negative age?');
            }
        }
    }
};

Шаг 2: Создайте прокси-объект

Создайте прокси-объект, как это:

let proxy = new Proxy(employee, validator);

Шаг 3: Назначьте не целочисленное значение для свойства, скажем, возраст

Попробуйте сделать это:

proxy.age = 'I am testing a blunder'; // string value

Вывод будет таким:

TypeError: Age is always an Integer, Please Correct it!
    at Object.set (E:\Projects\KOSS\metaprogramming\js-mtprog\proxy\userSetProxy.js:28:23)
    at Object. (E:\Projects\KOSS\metaprogramming\js-mtprog\proxy\userSetProxy.js:40:7)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3

Точно так же попробуйте сделать это:

p.age = -1; // will result in error

Как использовать прокси и размышлять

Вот пример обработчика, где мы используем методы из отражения API:

const employee = {
    firstName: 'Tapas',
    lastName: 'Adhikary'
};

let logHandler = {
    get: function(target, fieldName) {        
        console.log("Log: ", target[fieldName]);
        
        // Use the get method of the Reflect object
        return Reflect.get(target, fieldName);
    }
};

let func = () => {
    let p = new Proxy(employee, logHandler);
    p.firstName;
    p.lastName;
};

func();

Еще несколько случаев использования прокси

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

  • Защитить ID Поле объекта из удаления (ловушка: deleteproperty)
  • Чтобы проследить доступ к недвижимости (ловушка: Get, Set)
  • Для привязки данных (Trap: Set)
  • С отзывными ссылками
  • Манипулировать в поведение оператора

… и многое другое.

Пока концепция MetaProgramming Дает нам много власти, магия иногда может идти неправильно.

Будьте осторожны:

  • Слишком много волшебство ! Убедитесь, что вы понимаете его, прежде чем применить его.
  • Возможные хиты производительности, когда вы делаете невозможное возможное
  • Можно рассматривать как контратальная отладка.

Обобщить,

  • Отражать и Прокси отличные включения в JavaScript, чтобы помочь с MetaProgramming.
  • Многие сложные ситуации могут быть обработаны с их помощью.
  • Будьте в курсе нисходящих.
  • Символы ES6 Также можно использовать с вашими существующими классами и объектами, чтобы изменить свое поведение.

Я надеюсь, что вы нашли эту статью Insightful. Весь исходный код, используемый в этой статье, можно найти в моем Github Repository Отказ

Пожалуйста, поделитесь этой статьей, чтобы другие могли прочитать его. Вы можете у меня в Twitter ( @tapasadhary ) с комментариями или не стесняйтесь следовать за мной.