본문으로 건너뛰기
黯羽轻扬매일 조금씩

화살표 함수_ES6 노트 6

무료2026-03-05#JS#js箭头函数#js lambda表达式#js拉姆达表达式#javascript lambda expression#邱奇数#Y组合子

서문에

(이 글은 원래 지난주 콘텐츠였는데, 어제 쓰는 것을 잊어버렸습니다. 몰래 보충합니다)

최근 일이 조금 많아, sort 는 통과했지만, 여전히 약간 분주합니다. 하지만不管怎样, 계획은 거기에 있고, 최종적으로는 하나씩 완료될 것입니다

쓸데없는 말은 여기까지 하고, 어머니의 몸이 빨리 좋아지기를 바랍니다~

##一.화살표 함수简介

화살표 함수 (arrow function) 는 C# 의 lambda 표현식입니다. Java8 도 그것을 호화로운 점심에 추가했다고 합니다. 하지만不管怎样, JS 는 다른 언어로부터 우수한 특성을 흡수하고 있습니다 (예를 들어 yield, class, 기본 파라미터 등). 이러한 특성의 좋고 나쁨은 묻지 않고, 이 일 자체가 매우 좋은 것입니다 (적어도 우리가 사용하고 있는 것은 활력에 찬 도구입니다)

Java 는 -> 화살표를 사용하고, C# 이 사용하는 화살표는 JS 와 같습니다: =>. 이 화살표는 "lambda 연산자"라고 불리며, 업계 용어로는 "goes to"라고 읽습니다

lambda 표현식 (화살표 함수) 은 함수를 정의하는 가장 간결한 방법이라고 합니다. 구문상 거의 중복된 성분이 없습니다. JS 의 약타입 특징 때문에, JS 중의 lambda 표현식은 C# 이나 Java 중의 것보다 더욱 간결합니다 (파라미터 타입 선언이 적음)

한마디로, 화살표 함수는 lambda 표현식이며, 더 간결한 function 정의 방식을 제공합니다

##二.구문

arg => returnVal 구문은 함수를 생성하는 가장 간결한 방식으로, 형参가 arg, 반환값이 returnVal 인 function 을 정의합니다

다른 구문은 아래 표와 같습니다:

화살표 함수 구문
구문등가 코드의미
x => f(x)
function(x) {
    return f(x);
}
y=f(x)
(x, y)=>x + y;
function(x, y) {
    return x + y;
}
y=f(x,y)=x+y
(x, y)=>{g(x); g(y); return h(x, y);};
function(x, y) {
    g(x);
    g(y);
    return h(x, y);
}
          g(x), g(y)
y=f(x,y)==============h(x,y)
()=>({});
function() {
    return {};
}
y={}

P.S. 세 번째 열의 "의미" 는 수학 함수 의미를 가리키며, lambda 표현식은 원래 수학자가 만들어낸 것입니다

간단한 예는 다음과 같습니다:

// 간단한 예, 익명 함수 정의 간소화
var arr = [1, 3, 21, 12];
console.log(arr.map(x => 2 * x));   // [2, 6, 42, 24]
console.log(arr.sort((a, b) => a - b)); // [1, 3, 12, 21]
arr.forEach((item, index, arr) => {
    if (index %2 == 0) {
        console.log(item);
    }
    if (index == arr.length - 1) {
        console.log(`last item is ${item}`);
    }
});

복잡한 예:

// 복잡한 예
var app = {
    cache: {},
    ajax: function(url, callback) {
        var self = this;
        function req(url) {
            var res = `data from ${url}`;
            console.log(`ajax request ${url}`);
            // cache res
            self.cache[url] = res;
            return res;
        }
        var data = req(url);
        callback(data);
    }
}
app.ajax('http://www.xxx.xx', function(data) {
    console.log(`receive: ${data}`);
});
console.log(app.cache);

화살표 함수로 위 예를 개작:

// 화살표 함수로 개작
var es6App = {
    cache: {},
    ajax(url, callback) {
        var req = url => {
            var res = `data from ${url}`;
            console.log(`ajax request ${url}`);
            // cache res
            this.cache[url] = res;
            return res;
        }
        var data = req(url);
        callback(data);
    }
}
es6App.ajax('http://www.q.xx', function(data) {
    console.log(`receive: ${data}`);
});
console.log(es6App.cache);

that = this 라는 필요한 쓸데없는 말을 제거했습니다. 실제로는 한 항목의 원칙을 준수하면 모든 that = this 를 제거할 수 있습니다.下文의 주의사항 중의 3.this 에 대하여 참조

##三.특징 및 주의사항

###1.파라미터 리스트와 반환값의 구문

1 개의 파라미터일 때, 왼쪽에 직접 파라미터 이름을 쓰고, 0 개 또는 여러 개의 파라미터일 때, 파라미터 리스트는 () 로 감싸야 합니다

함수 본체가 1 조의 문만일 때, 오른쪽 값은 자동으로 함수 반환값이 되고, 함수 본체가 1 조를 초과하는 문일 때, 함수 본체는 {} 로 감싸야 하며,かつ 수동으로 return 해야 합니다

P.S. 물론, 쉽게 생각할 수 있는 것은 청홍조백을 가리지 않고,() => {} 를 화살표 함수의起手式으로 하는 것이지만, 이렇게 하는 것은 권장하지 않습니다. 왜냐하면 다음 조에서 { 는 모호하다고述べた通り, 번거로움을 가져올 수 있기 때문입니다

###2.모호한 문자

{유일1 개의 모호한 문자이므로, 오브젝트 리터럴을 반환할 때는 () 로 감싸야 합니다.否则블록 문으로 해석됩니다

예를 들어:

var f1 = () => {};
f1();   // undefined 를 반환
// 等価于
// var f1 = function() {};

var f2 = () => ({});
f2();   // 빈 오브젝트{}를 반환
// 等価于
// var f2 = function() {return {};};

###3.this 에 대하여

화살표 함수는외위 작용역에서 this 를 상속합니다. that = this 를 피하기 위해, 준수해야 합니다: 오브젝트 상의 직접 함수 속성값은 function 구문을 사용하는 외, 다른 함수는 모두 화살표 함수를 사용

이 규칙은 쉽게 이해할 수 있습니다. 예는 다음과 같습니다:

// 장면 1
function MyType() {}
MyType.prototype.fn = function() {/*화살표 함수 정의*/};  // 화살표 함수 중의 this 는 MyType 타입 인스턴스를 가리킴

// 장면 2
var obj = {};
obj.fn = function() {/*화살표 함수 정의*/};   // 화살표 함수 중의 this 는 obj 를 가리킴

차이는 function 키워드로 정의된 함수 속성 중에서, 해당 함수의 this 는 이 함수 속성이 소속된 오브젝트를 가리킵니다 (익명 함수의 this 는 global 오브젝트 또는 undefined 를 가리킴).说白了, function 은 새로운 this 를 정의할 수 있고, 화살표 함수는 할 수 없습니다. 그것은 외층에서 1 개의 this 를 빌릴 수밖에 없습니다. 따라서, 새로운 this 가 나타날 필요가 있을 때는 function 으로 함수를 정의하고, 외층의 this 를沿用하고 싶을 때는 화살표 함수를 사용합니다

###4.arguments 오브젝트에 대하여

화살표 함수에는 arguments 오브젝트가 없습니다. 왜냐하면 표준은 [기본 파라미터, 가변 파라미터](/articles/기본 파라미터와 부정 파라미터-es6 노트 4/), [파라미터 해체](/articles/destructuring(해체 대입)-es6 노트 5/) 의 사용을 장려하고 있기 때문입니다

예를 들어:

// 일반 함수
(function(a) {console.log(`a = ${a}, arguments[0] = ${arguments[0]}`)})(1);
// log print: a = 1, arguments[0] = 1

// 위와 등가인 화살표 함수
(a => console.log(`a = ${a}, arguments[0] = ${arguments[0]}`))(1);
// log print: Uncaught ReferenceError: arguments is not defined

이는 함수가 익명인지 여부와 무관하며, 규칙은 화살표 함수 중에서는 arguments 오브젝트에 액세스할 수 없습니다 (undefined). 다음과 같습니다:

// 비익명 함수
var f = a => console.log(`a = ${a}, arguments[0] = ${arguments[0]}`);
f(2);
// log print: Uncaught ReferenceError: arguments is not defined

##四.題外話

ES6 화살표 함수에 관해서는, 위의 콘텐츠로随心所欲에驾驭하는のに十分합니다.下面我们扯点别的(재미있는 것)

###1.JS 중에서 서포트하는 모든 화살표

ES6 까지, 현재 js 중에서 서포트하는 화살표
화살표의미
<!--단행 주석
-->행두에서 단행 주석을 나타내며, 다른 위치에서는 "趋向于" 를 나타냄 (n --> 0 은 n-- > 0 과 등가)
<=비교 연산자, 小于等于
=>화살표 함수

2 개의 단행 주석 구문을 보고 놀라지 마십시오. 역사적 원인ですが, 현재 모든 브라우저가 서포트합니다. 쓸모없습니다. 냉지식이죠

###2.lambda 연산과 邱奇數

lambda 연산 중에서 유일한 기초 데이터 타입은 함수입니다. 邱奇數 (church numerals) 는 고계 함수를 사용하여 常見의 기초 데이터 타입 (정수, 불리언 값, 鍵値對, 리스트 등) 을 나타냅니다

자연수는 모두 숫자, 邱奇數는 모두 함수입니다. 邱奇數의 n 은 n 계 함수이며, f^n(inc, base) === f(inc, f(inc, ...f(inc, base))) 입니다. 모든 邱奇數는 2 개의 파라미터를 가진 함수입니다

어떻게 함수로 자연수를 나타내는가? 콘텐츠는 비교적 많지만, 여기에 자연수 집의 작은 예를 1 개 줍니다:

// 자연수 집합 정의
var number = (function*(inc, base) {
    var n = zero;

    while(true) {
        yield n(inc, base);
        n = succ(n);
    }
})(inc, 0);
for (var n of number) {
    console.log(n); // 0, 1, 2, 3, 4
    if (n > 3) {
        break;
    }
}

邱奇數로 나타낸 자연수 집은 다음과 같습니다:

// 0, 1, 2
var zero = (inc, base) => base;
var one = (inc, base) => inc(base);
var two = (inc, base) => inc(inc(base));

// 後繼 함수 정의 f^n -> f^(n+1)
// succ = ln.lf.lx.f (n f x)
var succ = n => (inc, base) => inc(n(inc, base));

// 邱奇數 집합 정의
var church = (function*() {
    var fn = zero;

    while(true) {
        yield fn;
        fn = succ(fn);
    }
})();
// test
var [, , , three, four, five, six, seven] = church;
console.log(three(inc, 0)); // 3
console.log(four(inc, 0));  // 4
console.log(five(inc, 0));  // 5
console.log(six(inc, 0));   // 6
console.log(seven(inc, 0)); // 7

잘 생각하면세계는 정말로 기묘하다는 것을 발견합니다. 이것도 가능??흥미가 있는 분은 필자의 Demo 를 참조하십시오 (감법, 승법과 감법을 실장했습니다)

###3.Y 組合子와 함수형 프로그래밍

Y 組合子는 익명 재귀 함수를 실장할 수 있습니다

Y 組合子는 1 개의 함수입니다. 다음과 같습니다:

var Y = F => G(G), var G = slef => F(self(self))

그 중에 不動点의 개념이 있습니다. 不動点: 若 F(f) = f 라면, f 는 不動点입니다. Y 組合子 중에서, G(G) 는 不動点입니다

가정 현재 계승을 구하는 재귀 함수가 있다고 합니다:

var fact = n => n === 0 ? 1 : n * fact(n - 1);

이는 분명히 1 개의 익명 재귀가 아닙니다. fact 는 함수명이며, 그것을 재귀 호출하여 계승을 계산합니다. 그렇다면 어떻게 1 개의 익명의 재귀 함수를 실장하는가? 이것은 가능할까요?

Y 組合子로一发하면 됩니다. 다음과 같습니다:

// Y 組合子 정의
// var Y = F => G(G);
// var G = self => F(self(self));
var Y = F =>
    ((g => g(g))
        (g =>
            (F((...x) =>
                g(g)(...x)))));

// 익명 재귀로 계승 구하기 실장
var yFact = Y(f =>
    n => n === 0 ? 1 : n * f(n - 1));
console.log(yFact(5));  // 120

기묘하죠?함수형 프로그래밍 중에는 각종의 유사한 기묘한 변환이 있습니다. FP 의 이해 코스트, 실행 효율은 묻지 않고, 이러한 변환 자체가 몇 개의 재미있는 연구할 가치가 있는 것입니다. 사고에 조금 더 공간을 주고, cpu 를 달리게 합시다

##五.まとめ

lambda 표현식의 극한의 간결함은 매력적이며, 함수를 정의하는 것은 수학 공식을 쓰는 것과 같습니다. 함수형 프로그래밍을 지원하는 언어는 본래 이러해야 합니다

참고 자료

댓글

아직 댓글이 없습니다

댓글 작성