>  기사  >  웹 프론트엔드  >  JavaScript의 함수 합리화에 대한 자세한 설명

JavaScript의 함수 합리화에 대한 자세한 설명

青灯夜游
青灯夜游앞으로
2020-12-18 17:53:246449검색

JavaScript의 함수 합리화에 대한 자세한 설명

관련 추천: "javascript 비디오 튜토리얼"

최근 커뮤니티에서 기술 블로그를 보다가 우연히 function currying이라는 단어를 보았는데, js function currying을 손으로 써야 한다는 요구 사항도 있었습니다. 어드밴스드 커링이 뭔지 궁금해요? 들어본 적 없나요?

문제에 착수하고, 연구하고, 정리를 했습니다.

함수 커링이란 무엇인가요?

함수 커링이란 무엇인가요? 먼저 Wikipedia에서 어떻게 설명하는지 살펴보겠습니다.

컴퓨터 과학에서 Currying(영어: Currying)은 Currying 또는 Currying으로도 번역되며 여러 매개변수를 허용하는 함수를 단일 매개변수를 허용하는 함수로 변환하는 것입니다(원래는 함수의 첫 번째 인수를 취하고 나머지 인수를 받아들이고 결과를 반환하는 새 함수를 반환합니다.

이 기술은 Moses Schönfinkel과 Gottlob Frege가 발명했지만 논리학자 Haskell Gary의 이름을 따서 Christopher Strachey가 명명했습니다.

직관적으로 커링은 "일부 매개변수를 수정하면 나머지 매개변수를 받아들이는 함수를 얻게 된다"고 말합니다. 따라서 두 개의 변수가 있는 함수 y^x의 경우 y=2가 고정되어 있으면 하나의 변수가 있는 함수 2^x를 얻습니다.

커링의 개념은 실제로 이해하기 쉽게 복잡하지 않습니다. 매개변수의 일부만 함수에 전달하여 호출하고, 나머지 매개변수를 처리하는 함수를 반환하도록 합니다.

텍스트 설명이 아직 다소 추상적이라면 add 함수를 사용하여 간단한 함수 카레 구현을 만들어 보겠습니다.

// 普通的add函数
function add(x, y) {
    return x + y
}

// add函数柯里化后
var curryingAdd = function(x) {
  return function(y) {
    return x + y;
  };
};

// 函数复用
var increment = curryingAdd(1);
var addTen = curryingAdd(10);

increment(2);
// 3
addTen(2);
// 12

사실 add 함수의 x, y 매개변수는 x를 받는 함수를 사용하고 y 매개변수를 처리하는 함수를 반환하는 것으로 변경됩니다. 이제 개념은 더 명확해졌습니다. 즉, 매개변수의 일부만 전달하여 함수를 호출하고 나머지 매개변수를 처리하는 함수를 반환하도록 하는 것입니다.

카레 기능이 왜 필요한가요?

추가 함수의 커링에 대한 위의 내용을 읽은 후 질문이 생깁니다. 레이어를 캡슐화하는 데 그렇게 많은 노력을 들이는 것이 무슨 소용이 있습니까?

1. 매개변수 재사용

사실 add 함수의 첫 번째 커링 예제에서는 이미 함수 커링이 가져온 함수 재사용의 편리함을 다루었습니다. increment 함수와 addTen 함수를 빠르게 구현해 보겠습니다.

// 正常正则验证字符串 reg.test(txt)

// 函数封装后
function check(reg, txt) {
    return reg.test(txt)
}

check(/\d+/g, 'test')       //false
check(/[a-z]+/g, 'test')    //true

// Currying后
function curryingCheck(reg) {
    return function(txt) {
        return reg.test(txt)
    }
}

var hasNumber = curryingCheck(/\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)

hasNumber('test1')      // true
hasNumber('testtest')   // false
hasLetter('21212')      // false

위 예제는 일반적인 검증입니다. 일반적으로 check 함수를 직접 호출하면 되지만 실제로 숫자가 있는지 확인할 곳이 많습니다. , 첫 번째 매개변수 reg를 재사용해야 다른 곳에서 hasNumber, hasLetter 및 기타 함수를 직접 호출할 수 있으므로 매개변수를 재사용할 수 있고 호출하기가 더 편리합니다.

둘째, 미리 확인하세요
var on = function(element, event, handler) {
    if (document.addEventListener) {
        if (element && event && handler) {
            element.addEventListener(event, handler, false);
        }
    } else {
        if (element && event && handler) {
            element.attachEvent('on' + event, handler);
        }
    }
}

var on = (function() {
    if (document.addEventListener) {
        return function(element, event, handler) {
            if (element && event && handler) {
                element.addEventListener(event, handler, false);
            }
        };
    } else {
        return function(element, event, handler) {
            if (element && event && handler) {
                element.attachEvent('on' + event, handler);
            }
        };
    }
})();

위는 isSupport 매개변수를 먼저 결정하는 것입니다

var on = function(isSupport, element, event, handler) {
    isSupport = isSupport || document.addEventListener;
    if (isSupport) {
        return element.addEventListener(event, handler, false);
    } else {
        return element.attachEvent('on' + event, handler);
    }
}

프로젝트를 진행하는 과정에서 일부를 캡슐화할 수 있습니다. DOM 작업은 일반적이지만 위에서 작성하는 첫 번째 방법도 비교적 일반적이지만, 비교적 일반적인 작성 방법인 두 번째 작성 방법을 살펴보겠습니다. 첫 번째 작성 방법은 자체 실행한 다음 새 함수를 반환하는 것입니다. 매번 판단을 피하세요.

3. 지연된 계산/연산
Function.prototype.bind = function (context) {
    var _this = this
    var args = Array.prototype.slice.call(arguments, 1)

    return function() {
        return _this.apply(context, args)
    }
}

JS에서 자주 사용하는 바인드처럼 구현 메커니즘은 Currying입니다.

함수 커링은 어떻게 구현하나요?

일반적인 캡슐화 방법:

// 初步封装
var currying = function(fn) {
    // args 获取第一个方法内的全部参数
    var args = Array.prototype.slice.call(arguments, 1)
    return function() {
        // 将后面方法里的全部参数和args进行合并
        var newArgs = args.concat(Array.prototype.slice.call(arguments))
        // 把合并后的参数通过apply作为fn的参数并执行
        return fn.apply(this, newArgs)
    }
}

첫 번째는 예비 캡슐화입니다. 클로저를 통해 예비 매개변수를 저장한 후 나머지 인수를 얻어서 접합하고 마지막으로 커링이 필요한 함수가 실행됩니다.

하지만 위 함수에는 여전히 몇 가지 결함이 있습니다. 반환되면 매개변수를 하나만 더 확장할 수 있습니다. Currying(a)(b)(c)는 일반적으로 지원되지 않는 것 같습니다. , 이런 종류의 기능은 지원되지 않습니다. 어떤 경우에도 재귀를 사용하고 한 계층 더 캡슐화하는 것을 생각할 것입니다.

// 支持多参数传递
function progressCurrying(fn, args) {

    var _this = this
    var len = fn.length;
    var args = args || [];

    return function() {
        var _args = Array.prototype.slice.call(arguments);
        Array.prototype.push.apply(args, _args);

        // 如果参数个数小于最初的fn.length,则递归调用,继续收集参数
        if (_args.length < len) {
            return progressCurrying.call(_this, fn, _args);
        }

        // 参数收集完毕,则执行fn
        return fn.apply(this, _args);
    }
}

실제로는 예비를 기반으로 재귀 호출을 추가한 것입니다. 매개변수 수가 초기 fn.length보다 적으면 재귀가 계속 실행됩니다.

커링 함수 성능은 어떤가요?

Currying의 성능에 대해 다음 사항을 알아야 합니다.

  • 인수 개체에 액세스하는 것은 일반적으로 명명된 매개 변수에 액세스하는 것보다 약간 느립니다.
  • 일부 이전 버전의 브라우저에서는 인수.길이 구현이 상당히 느립니다.
  • 사용 fn.apply( … ) 및 fn.call( … )은 일반적으로 fn( … )을 직접 호출하는 것보다 약간 느립니다.
  • 많은 수의 중첩된 범위 및 클로저 함수를 생성하면 메모리와 속도 측면 모두에서 오버헤드가 발생합니다. 실제로 대부분의 애플리케이션에서 주요 성능 병목 현상은 DOM 노드를 운영하는 것입니다. js의 성능 손실은 기본적으로 무시할 수 있으므로 카레를 직접적이고 안전하게 사용할 수 있습니다.
커리 인터뷰 질문

// 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;

function add() {
    // 第一次执行时,定义一个数组专门用来存储所有的参数
    var _args = Array.prototype.slice.call(arguments);

    // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
    var _adder = function() {
        _args.push(…arguments);
        return _adder;
    };

    // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
    _adder.toString = function () {
        return _args.reduce(function (a, b) {
            return a + b;
        });
    }
    return _adder;
}

add(1)(2)(3)                // 6
add(1, 2, 3)(4)             // 10
add(1)(2)(3)(4)(5)          // 15
add(2, 6)(1)                // 9
요약

단순히 몇 가지 매개변수를 전달하면 실용적인 새 함수를 동적으로 생성할 수 있으며, 매개변수가 하나 이상 있어도 수학적 함수 정의가 유지된다는 추가적인 이점도 있습니다. .

커링 기능은 사용하기 매우 쉽고, 매일 사용하는 것이 저에게는 정말 즐겁습니다. 함수형 프로그래밍을 덜 번거롭고 지루하게 만드는 데 꼭 필요한 도구입니다.

더 많은 프로그래밍 관련 지식을 보려면 프로그래밍 소개를 방문하세요! !

위 내용은 JavaScript의 함수 합리화에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제