[javascript] ECMAScript 6에서 언제 화살표 기능을 사용해야합니까?

이 문제는 다가오는 ECMAScript 6 (하모니)의 맥락에서 코드 스타일에 대해 생각하고 이미 언어를 다루는 사람들을 대상으로합니다.

함께 () => {}그리고 function () {}우리는 ES6에서 함수를 작성하는 방법은 두 매우 비슷한 방법을 얻고있다. 다른 언어에서는 람다 함수가 종종 익명으로 구분되므로 ECMAScript에서는 모든 함수가 익명 일 수 있습니다. 두 유형 각각에는 고유 한 사용 도메인이 있습니다 (즉 this, 명시 적으로 또는 명시 적으로 바인드되지 않아야하는 경우). 이러한 영역들 사이에는 어느 쪽의 표기법이든 많은 경우가 있습니다.

ES6의 화살표 기능에는 최소한 두 가지 제한이 있습니다.

  • 작업 new할 때 작동하지 않으며 사용할 수 없습니다prototype
  • this초기화시 범위에 고정됨

이 두 가지 한계를 제외하고 화살표 기능은 이론적으로 거의 모든 위치에서 일반 기능을 대체 할 수 있습니다. 실제로 사용하는 올바른 방법은 무엇입니까? 화살표 기능을 사용해야합니까? 예 :

  • “어디서나 작동하는”즉, 함수가 this변수 에 대해 불가지론적일 필요 는 없으며 개체를 만들지 않습니다.
  • “어디서나 필요한 곳”, 즉 특정 범위에 바인딩해야하는 이벤트 리스너, 시간 초과
  • ‘짧은’기능은 있지만 ‘긴’기능은없는
  • 다른 화살표 기능이없는 기능 만

내가 찾고있는 것은 향후 ECMAScript 버전에서 적절한 기능 표기법을 선택하는 지침입니다. 이 지침은 팀의 개발자들에게 가르쳐 질 수 있도록 일관성을 유지해야하며, 한 기능 표기법에서 다른 기능 표기법으로 지속적으로 리팩토링 할 필요가 없도록 일관성을 유지해야합니다.



답변

얼마 전 우리 팀은 모든 코드 (중형 AngularJS 앱)를 Traceur Babel을 사용하여 컴파일 된 JavaScript로 마이그레이션했습니다 . ES6 이상의 기능에는 다음과 같은 경험 법을 사용하고 있습니다.

  • function전역 범위 및 Object.prototype속성에 사용하십시오 .
  • class객체 생성자에 사용 합니다.
  • =>다른 곳에서 사용하십시오 .

왜 거의 모든 곳에서 화살표 기능을 사용합니까?

  1. 범위 안전 : 화살표 기능을 일관되게 사용하면 모든 것이 thisObject루트 와 동일하게 사용 됩니다. 단일 표준 함수 콜백도 많은 화살표 함수와 혼합되어 있으면 범위가 엉망이 될 가능성이 있습니다.
  2. 소형화 : 화살표 기능을 읽고 쓰기가 더 쉽습니다. (이것은 의견이 올 수 있으므로 몇 가지 예를 더 제시 할 것입니다).
  3. 명확성 : 거의 모든 것이 화살표 함수 인 경우 function범위를 정의하기 위해 모든 규칙이 즉시 나타납니다. 개발자는 항상 다음으로 높은 function진술을 찾아서 무엇이 무엇인지 확인할 수 thisObject있습니다.

전역 범위 또는 모듈 범위에서 항상 일반 기능을 사용하는 이유는 무엇입니까?

  1. 에 액세스하면 안되는 기능을 나타냅니다 thisObject.
  2. window객체 (전역)을 가장 명시 적으로 언급이다.
  3. 많은 Object.prototype정의는 전체 범위 (생각 String.prototype.truncate등)에 있으며 일반적으로 function어쨌든 유형이어야 합니다. function전역 범위에서 일관되게 사용 하면 오류를 피할 수 있습니다.
  4. 전역 범위의 많은 함수는 구식 클래스 정의를위한 객체 생성자입니다.
  5. 함수 이름은 1로 지정할 수 있습니다 . 여기에는 두 가지 이점이 있습니다. (1) 쓰기 function foo(){}보다 덜 어색합니다.const foo = () => {} – 특히 외부의 다른 함수를 호출한다. (2) 기능 이름이 스택 추적에 표시됩니다. 모든 내부 콜백의 이름을 지정하는 것은 지루하지만, 모든 공용 함수의 이름을 지정하는 것이 좋습니다.
  6. 함수 선언된다 게양 정적 유틸리티 기능에 유용한 속성 인, (그들이 선언하기 전에 액세스 할 수 있음을 의미).

객체 생성자

화살표 함수를 인스턴스화하려고 시도하면 예외가 발생합니다.

var x = () => {};
new x(); // TypeError: x is not a constructor

화살표 함수에 비해 함수의 주요 장점 중 하나는 함수가 객체 생성자로 두 배가된다는 것입니다.

function Person(name) {
    this.name = name;
}

그러나 기능적으로 동일한 2 ES Harmony 초안 클래스 정의 는 거의 컴팩트합니다.

class Person {
    constructor(name) {
        this.name = name;
    }
}

나는 이전 표기법의 사용이 결국에는 낙담 될 것으로 예상한다. 객체 생성자 표기법은 객체가 프로그래밍 방식으로 생성되는 단순한 익명 객체 팩토리에 여전히 사용될 수 있지만 그 밖의 많은 것은 아닙니다.

객체 생성자가 필요한 경우 class위에 표시된 것처럼 함수를로 변환하는 것을 고려해야합니다 . 이 구문은 익명 함수 / 클래스에서도 작동합니다.

화살표 기능의 가독성

범위 기능이 손상 될 수있는 정규 기능을 고수하는 데있어 가장 좋은 주장은 화살표 기능을 일반 기능보다 읽기가 어렵다는 것입니다. 처음에 코드가 작동하지 않으면 화살표 기능이 필요하지 않을 수 있으며 화살표 기능을 일관되게 사용하지 않으면 추악하게 보입니다.

ECMAScript를 5.1이 우리에게 기능을 준 이후 ECMAScript를 아주 조금 변경되었습니다 Array.forEach, Array.map우리가 이러한 함수형 프로그래밍의 모든 기능에 대한-루프 이전에 사용되었을 것입니다 기능을 사용합니다. 비동기 JavaScript는 꽤 많이 시작되었습니다. ES6는 또한 Promise더 많은 익명의 기능을 의미 하는 객체를 제공 할 것입니다. 함수형 프로그래밍으로 돌아가는 것은 없습니다. 기능 JavaScript에서는 화살표 기능이 일반 기능보다 선호됩니다.

예를 들어이 코드 (특히 혼란) 조각을 가지고 3 :

function CommentController(articles) {
    this.comments = [];

    articles.getList()
        .then(articles => Promise.all(articles.map(article => article.comments.getList())))
        .then(commentLists => commentLists.reduce((a, b) => a.concat(b)));
        .then(comments => {
            this.comments = comments;
        })
}

정규 함수를 사용하는 동일한 코드 조각 :

function CommentController(articles) {
    this.comments = [];

    articles.getList()
        .then(function (articles) {
            return Promise.all(articles.map(function (article) {
                return article.comments.getList();
            }));
        })
        .then(function (commentLists) {
            return commentLists.reduce(function (a, b) {
                return a.concat(b);
            });
        })
        .then(function (comments) {
            this.comments = comments;
        }.bind(this));
}

화살표 기능 중 하나를 표준 기능으로 대체 할 수 있지만 그렇게하면 얻을 수있는 것이 거의 없습니다. 더 읽기 쉬운 버전은 무엇입니까? 나는 첫 번째를 말할 것입니다.

화살표 기능을 사용할지 또는 일반 기능을 사용할 지에 대한 질문은 시간이 지남에 따라 관련성이 떨어질 것이라고 생각합니다. 대부분의 함수function키워드를 없애는 클래스 메서드가되거나 클래스가됩니다. 를 통해 클래스를 패치하는 데 함수는 계속 사용됩니다 Object.prototype. 그 동안에는 function실제로 클래스 메소드 또는 클래스 여야하는 것에 대해 키워드를 예약하는 것이 좋습니다 .


노트

  1. 명명 된 화살표 기능은 ES6 사양에서 지연 되었습니다 . 여전히 향후 버전에 추가 될 수 있습니다.
  2. 초안 사양에 따르면 클래스가 키워드를 사용하지 않는 한 “클래스 선언 / 표현식은 함수 선언과 정확히 일치하는 생성자 함수 / 시제품 쌍을 만듭니다”라고extend 합니다. 사소한 차이점은 클래스 선언은 상수이지만 함수 선언은 상수가 아니라는 것입니다.
  3. 단일 명령문 화살표 함수의 블록에 대한 참고 사항 : 화살표 함수가 부작용 (예 : 할당)을 위해 호출되는 모든 위치에서 블록을 사용하고 싶습니다. 그렇게하면 반환 값을 버릴 수 있다는 것이 분명합니다.

답변

제안 에 따르면 , 화살표는 “전통적인 몇 가지 일반적인 문제점을 해결하고 해결하는 것”을 목표로 삼았습니다 Function Expression. 그들은 this어휘 적 으로 바인딩 하고 간결한 구문을 제공 하여 문제를 개선하려고했습니다 .

하나,

  • this어휘 적으로 일관되게 묶을 수 없다
  • 화살표 함수 구문은 섬세하고 모호합니다

따라서 화살표 함수는 혼동과 오류의 기회를 제공하며 JavaScript 프로그래머의 어휘에서 제외되고 function독점적으로 대체되어야 합니다.

어휘에 대하여 this

this 문제가있다 :

function Book(settings) {
    this.settings = settings;
    this.pages = this.createPages();
}
Book.prototype.render = function () {
    this.pages.forEach(function (page) {
        page.draw(this.settings);
    }, this);
};

화살표 함수 this는 콜백 내부의 속성에 액세스해야하는 문제를 해결하려고합니다 . 이미 여러 가지 방법이 있습니다 this. 변수에 할당하거나을 사용 bind하거나 Array집계 메소드 에서 사용 가능한 세 번째 인수를 사용할 수 있습니다 . 그러나 화살표가 가장 간단한 해결 방법 인 것처럼 보이므로 방법을 다음과 같이 리팩터링 할 수 있습니다.

this.pages.forEach(page => page.draw(this.settings));

그러나 코드가 jQuery와 같은 라이브러리를 사용했는지 여부를 고려하십시오 this. 이 메소드는 특별히 바인딩 됩니다. 이제 this다루어야 할 두 가지 값이 있습니다.

Book.prototype.render = function () {
    var book = this;
    this.$pages.each(function (index) {
        var $page = $(this);
        book.draw(book.currentPage + index, $page);
    });
};

우리는 사용해야합니다 function순서를 each결합하는 this동적. 여기서는 화살표 기능을 사용할 수 없습니다.

여러 this값을 다루는 것은 혼란 스러울 수 있습니다 this. 저자가 누구 에 대해 이야기 했는지 알기가 어렵 기 때문입니다 .

function Reader() {
    this.book.on('change', function () {
        this.reformat();
    });
}

저자는 실제로 전화하려고 했습니까 Book.prototype.reformat? 아니면 묶는 것을 잊고 this전화를 걸려 고 Reader.prototype.reformat했습니까? 핸들러를 화살표 함수로 변경하면 저자가 dynamic을 원했는지 궁금 this하지만 한 줄에 맞는 화살표를 선택했을 것입니다.

function Reader() {
    this.book.on('change', () => this.reformat());
}

“화살표가 때때로 사용하기에 잘못된 기능 일 수 있다는 것은 예외적인가? 아마도 우리가 동적 this값을 거의 필요로하지 않는다면 , 대부분의 시간에 화살표를 사용하는 것이 여전히 좋을 것이다.”

그러나 스스로에게 다음과 같이 질문하십시오. “코드를 디버깅하고 오류 결과가 ‘가장자리가 생긴 것’이라는 것을 알게 되었습니까?”대부분의 시간뿐만 아니라 문제를 피하는 것이 좋습니다. 시간의 100 %

더 나은 방법이 있습니다. 항상 사용하고 function( this항상 동적으로 바인딩 할 수 있음) 항상 this변수를 통해 참조 하십시오. 변수는 어휘이며 많은 이름을 가정합니다. this변수에 할당 하면 의도가 명확 해집니다.

function Reader() {
    var reader = this;
    reader.book.on('change', function () {
        var book = this;
        book.reformat();
        reader.reformat();
    });
}

또한, 항상this 변수에 할당 하면 (단일 this기능이 있거나없는 경우에도) 코드를 변경 한 후에도 의도를 명확하게 유지할 수 있습니다.

또한 동적 this은 거의 예외적입니다. jQuery는 5 천만 개가 넘는 웹 사이트에서 사용됩니다 (2016 년 2 월 현재 작성). this동적으로 바인딩하는 다른 API는 다음과 같습니다 .

  • Mocha (어제 최대 120k 다운로드)는을 통해 테스트 방법을 공개합니다 this.
  • Grunt (어제 ~ 63k 다운로드)는를 통해 빌드 작업을위한 메소드를 노출합니다 this.
  • 백본 (어제 ~ 22,000 회 다운로드)은 액세스하는 메소드를 정의합니다 this.
  • DOM과 같은 이벤트 API는 EventTargetwith를 참조하십시오 this.
  • 패치되거나 확장 된 프로토 타입 API는로 인스턴스를 참조합니다 this.

( http://trends.builtwith.com/javascript/jQueryhttps://www.npmjs.com을 통한 통계 )

this이미 동적 바인딩이 필요할 수 있습니다 .

어휘 this는 때때로 예상되지만 때로는 그렇지 않습니다. this때로는 역학 이 예상 되듯 이 때로는 그렇지 않습니다. 고맙게도 예상되는 바인딩을 항상 생성하고 전달하는 더 좋은 방법이 있습니다.

간결한 구문에 대하여

화살표 함수는 함수에 대한 “더 짧은 구문 형태”를 제공하는 데 성공했습니다. 그러나이 짧은 기능으로 더 성공할 수 있습니까?

인가 x => x * x보다 “읽기 쉽게” function (x) { return x * x; }? 아마도 한 줄의 짧은 코드를 생성 할 가능성이 높기 때문일 수 있습니다. 다이슨의 독서 속도와 선 길이가 화면 에서 읽는 효과에 미치는 영향 ,

보통 및 빠른 속도에서 효과적인 판독을 지원하는 중간 줄 길이 (한 줄에 55 자)가 나타납니다. 이것은 최고 수준의 이해력을 만들어 냈습니다. . .

조건부 (삼항) 연산자와 단일 행 if명령문에 대해서도 비슷한 근거가 있습니다.

그러나 실제로 제안서에 광고 된 간단한 수학 함수를 작성 하고 있습니까? 내 도메인은 수학적이지 않으므로 서브 루틴이 그렇게 우아하지는 않습니다. 오히려 화살표 함수가 열 제한을 깨고 편집기 또는 스타일 가이드로 인해 다른 줄로 줄 바꿈되어 다이슨의 정의에 따라 “가독성”이 무효화되는 것을 볼 수 있습니다.

“가능한 경우 짧은 기능을 위해 짧은 버전을 사용하는 것은 어떻습니까?” 그러나 이제는 문체 규칙이 언어 제약 조건과 모순됩니다. “가장 짧은 표기법 만 사용하고 때로는 가장 긴 표기법 만 this예상대로 묶는다는 점을 명심하십시오 .” 이러한 혼란은 화살을 특히 오용하기 쉽다.

화살표 함수 구문에는 여러 가지 문제가 있습니다.

const a = x =>
    doSomething(x);

const b = x =>
    doSomething(x);
    doSomethingElse(x);

이 두 기능은 구문 상 유효합니다. 그러나 doSomethingElse(x);의 본문에 있지는 않지만 b들여 쓰기가 잘 안된 최상위 문장 일뿐입니다.

블록 형식으로 확장하면 더 이상 암시 적이 없으므로 return복원하는 것을 잊을 수 있습니다. 그러나 그 표현은 부작용을 일으키기위한 것일 뿐이 므로 return앞으로 명시적인 것이 필요한지 누가 알 수 있습니까?

const create = () => User.create();

const create = () => {
    let user;
    User.create().then(result => {
        user = result;
        return sendEmail();
    }).then(() => user);
};

const create = () => {
    let user;
    return User.create().then(result => {
        user = result;
        return sendEmail();
    }).then(() => user);
};

rest 매개 변수로 의도 된 것은 스프레드 연산자로 구문 분석 될 수 있습니다.

processData(data, ...results => {}) // Spread
processData(data, (...results) => {}) // Rest

할당은 기본 인수와 혼동 될 수 있습니다.

const a = 1;
let x;
const b = x => {}; // No default
const b = x = a => {}; // "Adding a default" instead creates a double assignment
const b = (x = a) => {}; // Remember to add parens

블록은 객체처럼 보입니다 :

(id) => id // Returns `id`
(id) => {name: id} // Returns `undefined` (it's a labeled statement)
(id) => ({name: id}) // Returns an object

이것은 무엇을 의미 하는가?

() => {}

작성자가 no-op 또는 빈 객체를 반환하는 함수를 만들려고 했습니까? (염두에두고, 우리는 지금까지 배치해야합니다 {=>우리는 표현의 문법에 자신을 제한? 것이 더 화살표 ‘빈도를 줄일 것인가?.)

=>모양 <=>=:

x => 1 ? 2 : 3
x <= 1 ? 2 : 3

if (x => 1) {}
if (x >= 1) {}

화살표 함수 표현식을 즉시 호출하려면 ()외부에 배치 해야 하지만 ()내부에 배치 하는 것은 유효하며 의도적 일 수 있습니다.

(() => doSomething()()) // Creates function calling value of `doSomething()`
(() => doSomething())() // Calls the arrow function

그러나 (() => doSomething()());즉시 호출되는 함수 표현식을 작성하려는 의도로 작성 하더라도 아무 일도 일어나지 않습니다.

위의 모든 경우를 고려하여 화살표 기능이 “더 이해하기 쉽다”고 주장하기는 어렵습니다. 하나는 이 구문을 사용하는 데 필요한 모든 특별한 규칙을 배운다. 정말 가치가 있습니까?

의 구문 function은 예외적으로 일반화됩니다. function독점적으로 사용 한다는 것은 언어 자체가 혼란스러운 코드를 작성하지 못하게한다는 것을 의미합니다. 모든 경우에 구문 적으로 이해해야하는 절차를 작성하려면을 선택합니다 function.

지침에 대하여

“명확하고”일관성이 있어야하는 지침을 요청하십시오. 화살표 함수를 사용하면 구문 적으로 유효하고 논리적으로 유효하지 않은 코드가 생겨 두 함수 형태가 의미 있고 임의로 서로 얽혀 있습니다. 따라서 다음을 제공합니다.

ES6의 기능 표기법에 대한 지침 :

  • 로 절차를 작성하십시오 function.
  • 항상 this변수에 할당 하십시오. 사용하지 마십시오 () => {}.

답변

화살표 기능기능 을 단순화 scope하고 this키워드를 더 단순하게 하여 키워드를 해결 하기 위해 작성되었습니다 . =>화살표처럼 보이는 구문을 사용합니다 .

참고 : 기존 기능을 대체하지 않습니다. 모든 함수 구문을 화살표 함수로 바꾸면 모든 경우에 작동하지 않습니다.

기존 ES5 구문을 살펴 보도록하겠습니다. this키워드가 객체의 메서드 (객체에 속한 함수) 안에 있다면 무엇을 의미합니까?

var Actor = {
  name: 'RajiniKanth',
  getName: function() {
     console.log(this.name);
  }
};
Actor.getName();

위의 스 니펫은를 참조 object하고 이름을 인쇄합니다 "RajiniKanth". 아래의 스 니펫을 살펴보고 이것이 무엇을 지적하는지 봅시다.

var Actor = {
  name: 'RajiniKanth',
  movies: ['Kabali', 'Sivaji', 'Baba'],
  showMovies: function() {
   this.movies.forEach(function(movie) {
     alert(this.name + " has acted in " + movie);
   });
  }
};

Actor.showMovies();

this키워드가 내부 에 있다면 method’s function어떨까요?

여기서 이것은 타락한 window object것으로 inner function간주됩니다 scope. 때문에 this, 항상 함수의 소유자를 참조하는 것이이 경우에,에 -이 범위를 벗어나 지금부터 – 윈도우 / 전역 객체.

object의 메소드 안에있을 경우 — function소유자가 객체입니다. 따라서 this 키워드는 객체에 바인딩됩니다. 그러나 독립형 또는 다른 방법 내에서 함수 내부에있는 경우 항상 window/global오브젝트를 참조 합니다.

var fn = function(){
  alert(this);
}

fn(); // [object Window]

우리 ES5스스로이 문제를 해결할 수있는 방법이 있습니다. ES6 화살표 기능으로 들어가기 전에 그 문제를 해결하는 방법을 살펴 보겠습니다.

일반적으로 메서드의 내부 함수 외부에서 변수를 만듭니다. 이제이 ‘forEach’메소드 thisobject’s속성 및 해당 값에 액세스 할 수 있습니다.

var Actor = {
  name: 'RajiniKanth',
  movies: ['Kabali', 'Sivaji', 'Baba'],
  showMovies: function() {
   var _this = this;
   this.movies.forEach(function(movie) {
     alert(_this.name + " has acted in " + movie);
   });
  }
};

Actor.showMovies();

를 사용 하여 메소드를 나타내는 키워드 bind를에 첨부 this합니다 method’s inner function.

var Actor = {
  name: 'RajiniKanth',
  movies: ['Kabali', 'Sivaji', 'Baba'],
  showMovies: function() {
   this.movies.forEach(function(movie) {
     alert(this.name + " has acted in " + movie);
   }.bind(this));
  }
};

Actor.showMovies();

이제 ES6화살표 기능 lexical scoping을 사용하여 더 간단한 방법으로 문제를 처리 할 수 ​​있습니다 .

var Actor = {
  name: 'RajiniKanth',
  movies: ['Kabali', 'Sivaji', 'Baba'],
  showMovies: function() {
   this.movies.forEach((movie) => {
     alert(this.name + " has acted in " + movie);
   });
  }
};

Actor.showMovies();

Arrow functionsbind이것에 대한 것을 제외하고는 함수 문과 비슷합니다 parent scope. 경우] arrow function is in top scope, this인수를 참조한다 window/global scope일반 함수 안에 화살표 기능이 외부 함수와 같은 인수는이있는 반면,.

with arrow함수 thisscope생성시 둘러싸기에 바인딩되어 있으며 변경할 수 없습니다. 새로운 연산자 인 bind, call 및 apply는 이에 영향을 미치지 않습니다.

var asyncFunction = (param, callback) => {
  window.setTimeout(() => {
  callback(param);
  }, 1);
};

// With a traditional function if we don't control
// the context then can we lose control of `this`.
var o = {
  doSomething: function () {
  // Here we pass `o` into the async function,
  // expecting it back as `param`
  asyncFunction(o, function (param) {
  // We made a mistake of thinking `this` is
  // the instance of `o`.
  console.log('param === this?', param === this);
  });
  }
};

o.doSomething(); // param === this? false

위의 예에서 우리는 이것에 대한 통제력을 잃었습니다. 변수 참조를 this사용하거나를 사용 하여 위 예제를 해결할 수 있습니다 bind. ES6으로, 그것은 관리에 용이하게 this결합 그것으로 lexical scoping.

var asyncFunction = (param, callback) => {
  window.setTimeout(() => {
  callback(param);
  }, 1);
};

var o = {
  doSomething: function () {
  // Here we pass `o` into the async function,
  // expecting it back as `param`.
  //
  // Because this arrow function is created within
  // the scope of `doSomething` it is bound to this
  // lexical scope.
  asyncFunction(o, (param) => {
  console.log('param === this?', param === this);
  });
  }
};

o.doSomething(); // param === this? true

화살표 기능을 사용하지 않을 때

객체 리터럴 내부.

var Actor = {
  name: 'RajiniKanth',
  movies: ['Kabali', 'Sivaji', 'Baba'],
  getName: () => {
     alert(this.name);
  }
};

Actor.getName();

Actor.getName화살표 함수로 정의되지만 때문에 호출에 경고가 미정 this.nameundefined문맥에 남아 window.

화살표 함수는 컨텍스트를 어휘 적으로 window object… 즉 외부 범위 와 바인딩하기 때문에 발생합니다 . 실행 this.namewindow.name정의되지 않은와 같습니다.

객체 프로토 타입

에 메소드를 정의 할 때도 동일한 규칙이 적용됩니다 prototype object. sayCatName 메소드를 정의하기 위해 화살표 함수를 사용하는 대신 올바르지 않은 결과가 발생합니다 context window.

function Actor(name) {
  this.name = name;
}
Actor.prototype.getName = () => {
  console.log(this === window); // => true
  return this.name;
};
var act = new Actor('RajiniKanth');
act.getName(); // => undefined

생성자 호출

this구성 호출에서 새로 작성된 오브젝트입니다. 새 Fn ()을 실행할 때의 컨텍스트 constructor Fn는 새 객체 this instanceof Fn === true입니다.

this 엔 클로징 컨텍스트, 즉 새로 작성된 오브젝트에 지정되지 않는 외부 범위에서 설정됩니다.

var Message = (text) => {
  this.text = text;
};
// Throws "TypeError: Message is not a constructor"
var helloMessage = new Message('Hello World!');

동적 컨텍스트가있는 콜백

Arrow 함수 context는 선언시 정적으로 바인딩하며 동적으로 만들 수 없습니다. DOM 요소에 이벤트 리스너를 연결하는 것은 클라이언트 측 프로그래밍에서 일반적인 작업입니다. 이벤트는이를 대상 요소로하여 핸들러 기능을 트리거합니다.

var button = document.getElementById('myButton');
button.addEventListener('click', () => {
  console.log(this === window); // => true
  this.innerHTML = 'Clicked button';
});

this전역 컨텍스트에 정의 된 화살표 함수의 창입니다. click 이벤트가 발생하면 브라우저는 버튼 컨텍스트로 핸들러 함수를 호출하려고 시도하지만 화살표 함수는 사전 정의 된 컨텍스트를 변경하지 않습니다. this.innerHTML에 해당 window.innerHTML하고 아무 의미가 없습니다.

대상 요소에 따라이를 변경할 수있는 함수 표현식을 적용해야합니다.

var button = document.getElementById('myButton');
button.addEventListener('click', function() {
  console.log(this === button); // => true
  this.innerHTML = 'Clicked button';
});

사용자가 버튼을 클릭하면 핸들러 기능에서 버튼이됩니다. 따라서 this.innerHTML = 'Clicked button'클릭 한 상태를 반영하도록 단추 텍스트를 올바르게 수정합니다.

참조 :
https://dmitripavlutin.com/when-not-to-use-arrow-functions-in-javascript/


답변

화살표 기능-지금까지 가장 널리 사용되는 ES6 기능 …

사용법 : 다음 시나리오를 제외하고 모든 ES5 기능을 ES6 화살표 기능으로 교체해야합니다.

화살표 기능은 사용하지 않아야합니다.

  1. 기능 게양을 원할 때
    • 화살표 기능은 익명입니다.
  2. 함수에서

    this/ 를 사용하고 싶을 때arguments

    • 화살표 기능하지 않는 this/ arguments자신의, 그들은 그들의 외부 상황에 따라 다릅니다.
  3. 명명 된 함수를 사용하고 싶을 때
    • 화살표 기능은 익명입니다.
  4. 함수를 constructor
    • 화살표 기능에는 자체 기능이 없습니다 this.
  5. 객체 리터럴에서 속성으로 함수를 추가하고 객체를 사용하려는 경우
    • 액세스 할 수 없으므로 this(자체 자체이어야 함).

더 잘 이해하기 위해 화살표 함수의 변형을 이해합시다.

변형 1 : 함수에 둘 이상의 인수를 전달하고 함수에서 일부 값을 반환하려는 경우.

ES5 버전 :

var multiply = function (a,b) {
    return a*b;
};
console.log(multiply(5,6)); //30

ES6 버전 :

var multiplyArrow = (a,b) => a*b;
console.log(multiplyArrow(5,6)); //30

참고 :
function키워드는 필요하지 않습니다.
=>필요합니다.
{}우리가 제공하지 않을 {} return때 JavaScript에 의해 묵시적으로 추가되고 제공 {}할 때 필요할 return경우 추가 해야합니다.

변형 2 : 함수에 하나의 인수 만 전달하고 일부 값을 반환하려는 경우.

ES5 버전 :

var double = function(a) {
    return a*2;
};
console.log(double(2)); //4

ES6 버전 :

var doubleArrow  = a => a*2;
console.log(doubleArrow(2)); //4

참고 : 하나의 인수 만 전달하면 괄호를 생략 할 수 있습니다 ().

변형 3 : 함수에 인수를 전달하지 않고 값을 반환하지 않으려는 경우.

ES5 버전 :

var sayHello = function() {
    console.log("Hello");
};
sayHello(); //Hello

ES6 버전 :

var sayHelloArrow = () => {console.log("sayHelloArrow");}
sayHelloArrow(); //sayHelloArrow

변형 4 : 화살표 함수에서 명시 적으로 돌아 가려고 할 때.

ES6 버전 :

var increment = x => {
  return x + 1;
};
console.log(increment(1)); //2

변형 5 : 화살표 함수에서 객체를 반환하려고 할 때.

ES6 버전 :

var returnObject = () => ({a:5});
console.log(returnObject());

참고 : 객체를 괄호로 묶어야합니다. ()그렇지 않으면 JavaScript가 블록과 객체를 구분할 수 없습니다.

변형 6 : Arrow 함수에는 arguments외부 컨텍스트에 따라 달라지는 자체 객체 배열 이 없습니다 arguments.

ES6 버전 :

function foo() {
  var abc = i => arguments[0];
  console.log(abc(1));
};
foo(2); // 2

주 :
foo로하는 함수이다 ES5 arguments이되는 물체와 같은 배열 전달 인자 2이므로 arguments[0]대해 foo2이다.

abc그것은 자신의없는 년부터 ES6 기능을 화살표있다 arguments가 인쇄 따라서 arguments[0]foo대신의 외부 상황.

변형 7 : 화살표 기능에는 this외부 컨텍스트에 따라 고유 한 기능이 없습니다.this

ES5 버전 :

var obj5 = {
  greet: "Hi, Welcome ",
  greetUser : function(user) {
        setTimeout(function(){
        console.log(this.greet + ": " +  user); // "this" here is undefined.
        });
     }
};

obj5.greetUser("Katty"); //undefined: Katty

참고 : setTimeout에 전달 된 콜백은 ES5 함수이며 환경에 this정의되지 않은 자체 함수 가 use-strict있으므로 출력을 얻습니다.

undefined: Katty

ES6 버전 :

var obj6 = {
  greet: "Hi, Welcome ",
  greetUser : function(user) {
    setTimeout(() => console.log(this.greet + ": " +  user));
      // this here refers to outer context
   }
};

obj6.greetUser("Katty"); //Hi, Welcome: Katty

참고 : 전달 된 콜백 setTimeout기능을 화살표와 그것이 자신의가없는 ES6입니다 this그것이 외부 문맥의에서이 걸립니다 그래서 greetUser이있는 thisobj6우리가 출력을 얻을 따라서 :

Hi, Welcome: Katty

기타 :new 화살표 기능과 함께
사용할 수 없습니다 . 화살표 기능에는 prototype속성 이 없습니다 . 우리는 결합하지 않는 this기능을 통해 호출되는 화살표 때 applycall.


답변

지금까지의 훌륭한 답변 외에도 화살표 함수가 “일반적인”JavaScript 함수보다 근본적으로 더 나은 이유가 매우 다른 이유를 제시하고자합니다. 논의를 위해 TypeScript 또는 Facebook의 “Flow”와 같은 유형 검사기를 사용한다고 가정 해 봅시다. 유효한 ECMAScript 6 코드와 흐름 유형 주석 인 다음 완구 모듈을 고려하십시오.

export class C {
  n : number;
  f1: number => number;
  f2: number => number;

  constructor(){
    this.n = 42;
    this.f1 = (x:number) => x + this.n;
    this.f2 = function (x:number) { return  x + this.n;};
  }
}

이제 다음과 같이 다른 모듈에서 클래스 C를 사용할 때 어떤 일이 발생하는지 확인하십시오.

let o = { f1: new C().f1, f2: new C().f2, n: "foo" };
let n1: number = o.f1(1); // n1 = 43
console.log(n1 === 43); // true
let n2: number = o.f2(1); // n2 = "1foo"
console.log(n2 === "1foo"); // true, not a string!

보시다시피 , 유형 검사기는 여기에서 실패했습니다 : f2는 숫자를 반환해야하지만 문자열을 반환했습니다!

더 나쁜 것은, f2의 “this”가 f2의 인수 목록에서 발생하지 않으므로 “this”에 필요한 유형을 추가 할 수 없었기 때문에 생각할 수없는 유형 검사기 는 일반적인 (화살표가 아닌) JavaScript 함수를 처리 할 수없는 것 같습니다. f2에 대한 주석으로.

이 문제는 유형 검사기를 사용하지 않는 사람들에게도 영향을 줍니까? 우리는 정적 유형이 없어도 마치 마치 존재하는 것처럼 생각하기 때문에 그렇게 생각합니다. ( “첫 번째 매개 변수는 숫자, 두 번째 매개 변수는 문자열이어야합니다.”등) 숨겨진 “this”-인수는 함수 본문에 사용되거나 사용되지 않을 수 있으므로 정신 부기를 어렵게 만듭니다.

다음은 Babel에서 생성 된 실행 가능한 형식화되지 않은 버전입니다.

class C {
    constructor() {
        this.n = 42;
        this.f1 = x => x + this.n;
        this.f2 = function (x) { return x + this.n; };
    }
}

let o = { f1: new C().f1, f2: new C().f2, n: "foo" };
let n1 = o.f1(1); // n1 = 43
console.log(n1 === 43); // true
let n2 = o.f2(1); // n2 = "1foo"
console.log(n2 === "1foo"); // true, not a string!


답변

화살표 기능 this때문에 로컬에 액세스 할 필요가없는 항상 화살표 기능을 사용하는 것을 선호 합니다. 는 자신의 this, arguments, super 또는 new.target을 바인딩하지 선호 합니다.


답변

나는 여전히 첫 번째 답변에 쓴 모든 것을지지합니다 에 합니다. 그러나 코드 스타일에 대한 나의 의견은 그 이후로 발전했기 때문에 마지막 질문에 대한이 질문에 대한 새로운 대답이 있습니다.

어휘에 대하여 this

마지막 대답에서, 나는이 언어에 관해 내가 가지고있는 주장과 직접적으로 관련이 없기 때문에 내가 가지고있는 근본적인 믿음을 의도적으로 회피했다. 그럼에도 불구하고, 이것을 명시 적으로 언급하지 않으면 많은 사람들이 화살표가 너무 유용하다고 생각할 때 화살표를 사용하지 말 것을 권장하는 이유를 이해하는 이유를 이해할 수 있습니다.

내 생각은 이것이다 : 우리는 this처음에 사용해서는 안된다 . 따라서 사람 this이 자신의 코드에서 의도적으로 사용 하는 것을 피하면 this화살표 의 “어휘 “기능은 거의 가치가 없습니다. 또한 this나쁜 일 이라는 전제 하에서 , 화살의 대우 this는“좋은 일”이 아닙니다. 대신 다른 나쁜 언어 기능에 대한 일종의 손상 제어입니다.

나는 이것이 어떤 사람들에게 발생하지는 않지만, 그것이 어떤 사람들에게도 발생한다는 것을 알고 있습니다. this 파일 당 수백 번 나타나는 있으며 약간의 (또는 많은) 손상 제어가 모두 필요합니다 합리적인 사람이 희망 할 수 있습니다. 따라서 화살은 나쁜 상황을 더 좋게 만들 때 어떤 식 으로든 좋을 수 있습니다.

this화살표가없는 것보다 화살표가있는 코드를 작성하는 것이 더 쉬운 경우에도 화살표 사용 규칙은 매우 복잡합니다 (현재 스레드 참조). 따라서 귀하가 요청한대로 지침은 “명확하지 않고” “일관되지 않습니다”. 프로그래머가 화살표의 모호성에 대해 알고 있더라도 어휘의 가치가 this그림자를 어둡게 하기 때문에 어쨌든 그것을 으 rug하고 받아들입니다 .

이 모든 것은 다음과 같은 실현의 서문입니다. 하나를 사용하지 않으면 일반적으로 해당 화살표 this에 대한 모호성 this은 관련이 없습니다. 이 상황에서 화살표는 더 중립이됩니다.

간결한 구문에 대하여

첫 번째 답변을 썼을 때 모범 사례에 대한 노예 준수조차도 더 완벽한 코드를 생성 할 수 있다면 지불해야 할 가치가 있다고 생각했습니다. 그러나 결국 간결함이 코드 품질을 향상시킬 수있는 추상화의 형태로 작용할 수 있다는 사실을 알게되었습니다.

다시 말해, 젠장, 나도 하나의 라이너 기능을 원한다!

지침에 대하여

가능성으로 this중립적 인 화살표 기능과 추구 할 가치가 다음과 같은보다 관대 한 지침을 제공합니다.

ES6의 기능 표기법에 대한 지침 :

  • 를 사용하지 마십시오 this.
  • 이름으로 호출 할 함수 (호이스트되기 때문에)에 함수 선언을 사용하십시오.
  • 콜백에는 화살표 기능을 사용하십시오.