Каррирование JavaScript

Node.js задняя часть внешний интерфейс JavaScript

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

Предположим, что библиотека функций предоставляет такую ​​функцию для объединения URL-адресов:

function simpleURL(protocol, domain, path) {
    return protocol + "://" + domain + "/" + path;
}
simpleURL('http','www.jackzxl.net', 'index.html');      //http://www.jackzxl.net/index.html

Это самая распространенная функция, в которой нет ничего нового. Но для вашего сайта первый параметр фиксируется на http, а второй параметр фиксируется наwww.jackzxl.net, единственное, что нужно изменить, это третий параметр. То есть для любой страницы или ресурса вашего сайта всегда фиксированы первые два параметра, а менять нужно только третий параметр.

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

function simpleURL(path) {
    return "http://www.jackzxl.net/" + path;
}

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

Каррирование означает привязку функции к подмножеству ее аргументов и возврат новой функции. Если это кажется более абстрактным, вы можете провести некоторые аналогии, например частичную специализацию в шаблонах C++, что облегчит понимание. Карри приведенный выше пример:

var myURL = simpleURL.bind(null, 'http', 'www.jackzxl.net');
myURL('myfile.js');     //http://www.jackzxl.net/myfile.js

//站点加上SSL
var mySslURL = simpleURL.bind(null, 'https', 'www.jackzxl.net');
mySslURL('myfile.js');  //https://www.jackzxl.net/myfile.js

Приведенный выше код использует привязку для реализации каррирования. Давайте вернемся назад и снова испытаем каррирование определений: привязываем функцию к подмножеству ее аргументов и возвращаем новую функцию. Обнаружено, что после каррирования функции становятся более гибкими и плавными, что является кратким способом реализации делегирования функций.

Зачем использовать привязку для достижения каррирования? Поскольку это просто, вам не нужно создавать собственные колеса, если у вас есть готовые. Но поскольку в этой статье рассказывается о каррировании, давайте реализуем каррирование сами, чтобы углубить наше понимание. Он должен удовлетворять двум вещам: подмножеству параметров и новой функции, которая возвращает:

var currying = function(fn) {
    var args = [].slice.call(arguments, 1);
    return function() {
        var newArgs = args.concat([].slice.call(arguments));
        return fn.apply(null, newArgs);
    };
};

var myURL2 = currying(simpleURL, 'https', 'www.jackzxl.net');
myURL2('myfile.js');    //http://www.jackzxl.net/myfile.js

Эффект такой же, как и при использовании bind. Давайте внимательно проанализируем пользовательскую функцию каррирования. Во-первых, параметр fn — это функция simpleURL, которую нужно каррировать, а последние — все переменные параметры (аргументы функции см.здесь), результат выполнения каждой строки кода в каррировании выглядит следующим образом:

var currying = function(fn) {
    var args = [].slice.call(arguments, 1);
    //args为["https", "www.jackzxl.net"]

    return function() {
        var newArgs = args.concat([].slice.call(arguments));
        //newArgs为["https", "www.jackzxl.net", "myFile.js"]

        return fn.apply(null, newArgs);
        //相当于return simpleURL("https", "www.jackzxl.net", "myFile.js");
    };
};

Принцип и реализация каррирования были объяснены выше. Так что же делает каррирование? Общие эффекты:

  • Повторное использование параметра
  • Отложенная операция
  • Плоский

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

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

Плоскийфункция более читабельна. Например, вы хотите получить заголовок всех статей из JSON-данных сайта:

//JSON数据
{
    "user": "Jack",
    "posts": [
        { "title": "JavaScript Curry", "contents": "..." },
        { "title": " JavaScript Function", "contents": "..." }
    ]
}

//从JSON数据中获取所有文章的title
fetchFromServer()
    .then(JSON.parse)
    .then(function(data){ return data.posts })
    .then(function(posts){
        return posts.map(function(post){ return post.title })
    })

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

var curry = require('curry');
var get = curry(function(property, object){ return object[property] });

fetchFromServer()
    .then(JSON.parse)
    .then(get('posts'))
    .then(map(get('title')))

Вернуться раньше?

Наконец, еще одна функция в Интернете — возвращаться заранее.Например, события IE отличаются от других браузеров.Для достижения совместимости это можно реализовать так:

function addHandler(target, eventType, handler){
    if (target.addEventListener){
        target.addEventListener(eventType, handler, false);
    } else {        //IE
        target.attachEvent("on" + eventType, handler);
    }
}

Но есть проблема с вышеизложенным: каждый раз, когда вызывается функция addHandler, выполняется оценка if...else. Здравый смысл подсказывает нам, что если пользователь не меняет браузеры во время выполнения (если это реально), его нужно определить только один раз, когда пользователь подключается к сайту в первый раз, и последующие вызовы не нужно проверять снова.

Этого можно добиться с помощью функции каррирования, которая возвращает новую функцию:

var addEvent = (function(){
    if (target.addEventListener) {
        return function(target, eventType, handler) {
            target.addEventListener(eventType, handler, false);
        };
    } else {        //IE
        return function(target, eventType, handler) {
            target.attachEvent("on" + eventType, handler);
        };
    }
})();   

Но, на мой взгляд, каррирование здесь не имеет особого смысла. Поскольку у каррирования много преимуществ, недостатки также очевидны, то есть стоимость обучения немного высока. При использовании каррирования для достижения «раннего возврата» стоимость обслуживания перевешивает преимущества.

Как это сделать без каррирования? Тернарный оператор делает свое дело:

var addHandler = document.body.addEventListener ?
    function(target, eventType, handler){
        target.addEventListener(eventType, handler, false);
    } :
    function(target, eventType, handler){
        target.attachEvent("on" + eventType, handler);
    };

Или перепишите функцию внутри функции:

function addHandler(target, eventType, handler){
    if (target.addEventListener){
        addHandler = function(target, eventType, handler){  //重写该函数
            target.addEventListener(eventType, handler, false);
        };
    } else {        //IE
        addHandler = function(target, eventType, handler){  //重写该函数
            target.attachEvent("on" + eventType, handler);
        };
    }
    addHandler(target, eventType, handler); //调用新函数
}

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

Суммировать

Хотя у карри загадочное название, на самом деле оно не таинственное. Во внешнем интерфейсе не так много приложений (конечно, у меня может быть меньше опыта), и больше следует использовать во внутренних асинхронных функциях, таких как Node.js.Для асинхронных API каррирование может уменьшить вложенность обратных вызовов.

https://www.jianshu.com/p/9b6b5c7527fc