var functionName = function () {} vs 함수 functionname () {}


질문

 

최근에 다른 사람의 JavaScript 코드를 유지하기 시작했습니다.나는 버그를 고치고, 기능을 추가하고 코드를 정리하고 더 일관성있게 만들려고합니다.

이전 개발자는 기능을 선언하는 두 가지 방법을 사용했으며 그 뒤에 이유가 있거나 그렇지 않은 이유가 있으면 운동을 할 수 없습니다.

두 가지 방법은 다음과 같습니다.

var functionOne = function() {
    // Some code
};
function functionTwo() {
    // Some code
}

이 두 가지 방법을 사용하는 이유는 무엇이며 각각의 장단점은 무엇입니까?다른 방법으로 할 수없는 한 가지 방법으로 수행 할 수있는 일이 있습니까?


답변

 

그 차이점은 기능이 함수 표현식이며 해당 줄에 도달 할 때만 정의되는 반면, 함수는 함수 선언이며 주변 함수 또는 스크립트가 실행되는 즉시 정의됩니다 (호이치로 인해).

예를 들어 함수 식 :

// TypeError : functionOne이 함수가 아닙니다 functionOne (); var functionOne = function () { console.log ( "Hello!"); };

기능 선언 :

// 출력 : "Hello!" functiontwo (); 함수 functionTwo () { console.log ( "Hello!"); }

역사적으로 블록 내에서 정의 된 함수 선언은 브라우저간에 일관성없이 취급되었습니다.엄격한 모드 (ES5에서 도입 된)는 묶는 블록에 함수 선언을 범위 지정하여이를 해결했습니다.

'엄격한 사용'; {//이 블록에 유의하십시오! 함수 functhree () { console.log ( "Hello!"); } } functionThree ();// ReferenceError



답변

먼저 GREG를 수정하고 싶습니다. ABC () {}도 범위가 지정됩니다. ABC 이름은이 정의가 발생한 범위에서 정의됩니다.예시:

function xyz(){
  function abc(){};
  // abc is defined here...
}
// ...but not here

둘째, 두 가지 스타일을 결합 할 수 있습니다.

var xyz = function abc(){};

XYZ는 평소와 같이 정의 될 것입니다. ABC는 모든 브라우저에서 정의되지 않지만 Internet Explorer는 정의되는 것에 의존하지 않습니다.그러나 그것은 본문 안에 정의 될 것입니다 :

var xyz = function abc(){
  // xyz is visible here
  // abc is visible here
}
// xyz is visible here
// abc is undefined here

모든 브라우저에서 별칭 함수를 사용하려면이 종류의 선언을 사용하십시오.

function abc(){};
var xyz = abc;

이 경우 XYZ와 ABC는 모두 동일한 객체의 별칭입니다.

console.log(xyz === abc); // prints "true"

결합 된 스타일을 사용하는 하나의 강력한 이유는 함수 개체의 "이름"속성 (Internet Explorer에서 지원하지 않음)입니다.기본적으로 다음과 같은 함수를 정의 할 때

function abc(){};
console.log(abc.name); // prints "abc"

그 이름은 자동으로 할당됩니다.그러나 당신이 그것을 정의 할 때

var abc = function(){};
console.log(abc.name); // prints ""

그 이름은 비어 있습니다 - 익명의 함수를 만들고 일부 변수에 할당했습니다.

결합 된 스타일을 사용하는 또 다른 좋은 이유는 외부 사용자에게 긴 비 차는 이름을 제공하면서 짧은 내부 이름을 사용하여 짧은 내부 이름을 사용하는 것입니다.

// Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
  // Let it call itself recursively:
  shortcut(n - 1);
  // ...
  // Let it pass itself as a callback:
  someFunction(shortcut);
  // ...
}

위의 예에서 우리는 외부 이름과 동일하게 할 수 있지만 너무 다루기거나 (그리고 느리게) 될 것입니다.

(자체를 참조하는 또 다른 방법은 여전히 비교적 길어지며 엄격한 모드에서 지원되지 않는 인수를 사용하는 것입니다.)

깊은 아래로, JavaScript는 서로 다르게 두 문을 취급합니다.이것은 함수 선언입니다.

function abc(){}

ABC는 현재 범위의 모든 곳에서 정의됩니다.

// We can call it here
abc(); // Works

// Yet, it is defined down there.
function abc(){}

// We can call it again
abc(); // Works

또한, 그것은 반환 진술을 통해 호이스트 됨 :

// We can call it here
abc(); // Works
return;
function abc(){}

이것은 함수 표현식입니다.

var xyz = function(){};

Xyz는 할당 시점에서 정의됩니다.

// We can't call it here
xyz(); // UNDEFINED!!!

// Now it is defined
xyz = function(){}

// We can call it here
xyz(); // works

기능 선언 대 기능 표현식은 그렉이 시연 한 차이가있는 이유입니다.

재미있는 사실:

var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"

개인적으로, 나는이 가시성을 제어 할 수 있기 때문에 "함수 표현"선언을 선호합니다.내가 함수를 정의 할 때

var abc = function(){};

나는 그 기능을 국지적으로 정의했다는 것을 알고 있습니다.내가 함수를 정의 할 때

abc = function(){};

저는 내가 전 세계적으로 내가 Scopes 체인의 어느 곳에서나 ABC를 정의하지 않았 음을 알고 있음을 알고 있습니다.이 스타일의 정의는 eval () 내부에서 사용되는 경우에도 탄력적입니다.정의는

function abc(){};

컨텍스트에 따라 다르며 실제로 정의 된 위치를 추측 할 수 있습니다. 특히 eval ()의 경우 답변은 다음과 같습니다. 브라우저에 따라 다릅니다.



답변

다음은 함수를 만드는 표준 양식에 대한 런 다운입니다. (원래 다른 질문을 위해 작성되었지만 정식 질문으로 이동 한 후에 적응했습니다.)

자귀:

ES5 : ECMAScript 5th Edition, 2009. ES2015 : ECMAScript 2015 ( "ES6"라고도 함)

빠른 목록 :

기능 선언 "익명"함수 표현식 (용어에도 불구하고 때로는 이름이있는 기능을 만듭니다) 이름 지정된 함수 표현식 접근 자 함수 이니셜 라이저 (ES5 +) 화살표 기능 표현식 (ES2015 +) (익명 함수 표현식과 마찬가지로 명시 적 이름이 포함되지 않고 이름이 아닌 함수를 만들 수 있습니다) 객체 이니셜 라이저의 메소드 선언 (ES2015 +) 클래스의 생성자 및 메소드 선언 (ES2015 +)

기능 선언

첫 번째 양식은 함수 선언이므로 다음과 같습니다.

function x() {
    console.log('x');
}

함수 선언은 선언입니다.진술이나 표현이 아닙니다.따라서, 당신은 그것을 따르지 않습니다.(그렇게하지는 않지만 무해합니다.).

단계별 코드가 실행되기 전에 실행이 나타나는 컨텍스트가 실행될 때 기능 선언이 처리됩니다.생성 된 함수는 위의 예제 (위의 예제에서 x)가 제공되며 해당 이름은 선언이 나타나는 범위에 저장됩니다.

동일한 컨텍스트에서 단계별 코드가 발생하기 전에 처리되므로 다음과 같이 할 수 있습니다.

x(); // Works even though it's above the declaration
function x() {
    console.log('x');
}

ES2015까지, 사양은 시도, if, 스위치, 동안, while, 등등 등의 제어 구조물 안에 함수 선언을 넣으면 자바 스크립트 엔진이해야 할 일을 포함하지 않았습니다.

if (someCondition) {
    function foo() {    // <===== HERE THERE
    }                   // <===== BE DRAGONS
}

단계별 코드가 실행되기 전에 처리되기 때문에 제어 구조에있을 때 수행해야 할 일을 알게됩니다.

이 작업은 ES2015까지 지정되지 않았지만 블록에서 함수 선언을 지원하는 허용 확장자였습니다.불행히도 (필연적으로) 다른 엔진은 다른 것들을했습니다.

ES2015에서 사양은 무엇을 해야할지 말합니다.실제로, 그것은 세 가지 분리 된 것들을 제공합니다.

  1. If in loose mode not on a web browser, the JavaScript engine is supposed to do one thing
  2. If in loose mode on a web browser, the JavaScript engine is supposed to do something else
  3. If in strict mode (browser or not), the JavaScript engine is supposed to do yet another thing

느슨한 모드에 대한 규칙은 까다 롭지 만 엄격한 모드에서는 블록의 기능 선언이 쉽습니다. 블록의 로컬 (블록 스코프가 있으며, 이는 ES2015의 새로운 기능)이며, 상단에 호이 스위에 가입했습니다.블록의.그래서:

"use strict";
if (someCondition) {
    foo();               // Works just fine
    function foo() {
    }
}
console.log(typeof foo); // "undefined" (`foo` is not in scope here
                         // because it's not in the same block)

"익명"함수 표현식

두 번째 일반적인 양식을 익명의 함수 표현식이라고합니다.

var y = function () {
    console.log('y');
};

모든 표현식과 마찬가지로 코드를 단계별로 실행할 때까지 평가됩니다.

ES5 에서이 기능이 생성 된 함수는 이름이 없습니다 (익명).ES2015에서는 가능한 경우 해당 기능이 컨텍스트에서 추론하여 가능한 경우 이름이 지정됩니다.위의 예에서 이름은 y입니다.함수가 속성 이니셜 라이저의 값 인 경우 유사한 기능이 수행됩니다.(이 일이 발생하는 경우에 대한 자세한 내용은 사양에서 setFunctionName을 검색합니다.

이름 지정된 함수 표현식

세 번째 양식은 명명 된 함수 표현식 ( "NFE")입니다.

var z = function w() {
    console.log('zw')
};

이 기능을 생성하면 적절한 이름이 있습니다 (이 경우 W).모든 표현식과 마찬가지로 코드를 단계별로 실행할 때도 평가됩니다.함수의 이름은식이 나타나는 범위에 추가되지 않습니다.이름은 함수 자체 내에서 범위에 있습니다.

var z = function w() {
    console.log(typeof w); // "function"
};
console.log(typeof w);     // "undefined"

NFE는 자바 스크립트 구현을위한 버그 소스가 자주 발생했습니다.예를 들어, 예를 들어 NFE를 완전히 잘못 처리하여 두 가지 다른 시간에 두 가지 다른 기능을 만듭니다.사파리의 초기 버전은 문제가있었습니다.좋은 소식은 현재 버전의 브라우저 (IE9 이상, 현재 Safari) 더 이상 문제가되지 않는다는 것입니다.(그러나이 글쓰기에서, 슬프게도, IE8은 광범위하게 사용되고 웹에 대한 코드를 사용하여 NFE를 사용하여 일반적으로 문제가 아직 문제가됩니다.)

접근 자 함수 이니셜 라이저 (ES5 +)

때로는 기능이 크게 눈에 띄지 않게 몰래 들어갈 수 있습니다.그것이 접근 자 기능이있는 경우입니다.다음은 예제입니다.

var obj = {
    value: 0,
    get f() {
        return this.value;
    },
    set f(v) {
        this.value = v;
    }
};
console.log(obj.f);         // 0
console.log(typeof obj.f);  // "number"

이 기능을 사용했을 때 나는 ()를 사용하지 않았습니다.그것이 속성에 대한 접근자 기능이기 때문입니다.우리는 정상적인 방법으로 속성을 얻고 설정하지만 장면 뒤에는 함수가 호출됩니다.

object.defineproperty, object.defineproperties 및 object.create에 대한 덜 알려진 두 번째 인수를 사용하여 접근 자 함수를 만들 수도 있습니다.

화살표 기능 식 (ES2015 +)

ES2015는 화살표 기능을 제공합니다.여기에 하나의 예가 있습니다.

var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6

지도 () 호출에 숨어있는 n => n * 2 뭔가를 확인하십시오.그것은 함수입니다.

화살표 기능에 대한 몇 가지 사항 :

  1. They don't have their own this. Instead, they close over the this of the context where they're defined. (They also close over arguments and, where relevant, super.) This means that the this within them is the same as the this where they're created, and cannot be changed.

  2. As you'll have noticed with the above, you don't use the keyword function; instead, you use =>.

위의 n => n * 2 예제는 이들의 한 형태입니다.함수를 전달하기 위해 여러 인수가있는 경우, 팬란을 사용합니다.

var a = [1, 2, 3];
var b = a.map((n, i) => n * i);
console.log(b.join(", ")); // 0, 2, 6

(Array # 맵은 항목을 첫 번째 인수로 전달하고 두 번째 인덱스로 인덱스를 전달합니다.)

두 경우 모두 함수의 본문은 단지 표현입니다.함수의 반환 값은 자동으로 해당 표현식의 결과가됩니다 (명시 적 수신을 사용하지 않음).

단일 표현식 이상을 수행하는 경우 {} 및 명시 적 반환 (값을 반환 해야하는 경우)을 정상으로 사용하십시오.

var a = [
  {first: "Joe", last: "Bloggs"},
  {first: "Albert", last: "Bloggs"},
  {first: "Mary", last: "Albright"}
];
a = a.sort((a, b) => {
  var rv = a.last.localeCompare(b.last);
  if (rv === 0) {
    rv = a.first.localeCompare(b.first);
  }
  return rv;
});
console.log(JSON.stringify(a));

{...}가없는 버전은 표현 본문 또는 간결한 본문이있는 화살표 기능이라고합니다.(또한 : 간결한 화살표 기능). 몸체를 정의하는 {...}가있는 것은 기능 본문이있는 화살표 기능입니다.(또한 : 자세한 화살표 기능).

객체 이니셜 라이저의 메소드 선언 (ES2015 +)

ES2015는 메소드 정의라는 함수를 참조하는 특성을 선언하는 짧은 형태를 허용합니다.다음과 같습니다.

var o = {
    foo() {
    }
};

ES5와 이전에 거의 동등한 것은 다음과 같습니다.

var o = {
    foo: function foo() {
    }
};

차이 (자세한 자세한 것 이외)는 메소드가 슈퍼를 사용할 수 있지만 함수는 할 수 없다는 것입니다.예를 들어, 메소드 구문을 사용하여 valueOf (say) valueOf를 사용하여 슈퍼 .valueOf ()를 사용하여 값 object.prototype.valueOf가 반환되면 (아마도 다른 것을 수행하기 전에) 반환 할 수 있습니다.ES5 버전은 object.prototype.valueof.call (이)을 대신해야합니다.

또한 메소드가 정의 된 오브젝트에 대한 참조가 있으므로 해당 객체가 임시 일시적이면 (예를 들어, 소스 오브젝트 중 하나로 object.Assign으로 전달하는 것이 좋습니다), 메소드 구문은객체는 메모리에 유지됩니다 (JavaScript 엔진이 해당 상황을 탐지하지 않고 슈퍼를 사용하는 경우 해당 상황을 처리하고 처리하지 않는 경우).

클래스의 생성자 및 메소드 선언 (ES2015 +)

ES2015는 선언 된 생성자 및 방법을 포함하여 미국 클래스 구문을 제공합니다.

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    getFullName() {
        return this.firstName + " " + this.lastName;
    }
}

위의 두 가지 함수 선언이 있습니다 : 이름 사람을 가져 오는 생성자 및 getFullName 용입니다. person.prototype에 할당 된 함수입니다.



답변

Global Context, 둘 다 var 문 및 End의 함수가 모두 전역 개체에 비 삭제 가능한 속성을 생성하지만 두 값의 값을 덮어 쓸 수 있습니다.

두 가지 방식의 미묘한 차이점은 변수 인스턴스화 프로세스가 var로 선언 된 모든 식별자가 undefined로 초기화되고 함수가 사용하는 것들이 사용되는 모든 식별자가 해당 순간 이후에 사용할 수있게됩니다.

 alert(typeof foo); // 'function', it's already available
 alert(typeof bar); // 'undefined'
 function foo () {}
 var bar = function () {};
 alert(typeof bar); // 'function'

bar functionExpression의 할당은 런타임까지 발생합니다.

FunctionDeclaration에 의해 생성 된 글로벌 속성은 변수 값과 같은 문제없이 덮어 쓸 수 있습니다.

 function test () {}
 test = null;

두 가지 예에서 또 다른 분명한 차이점은 첫 번째 함수가 이름이 없지만 두 번째 기능은 디버깅 할 때 실제로 유용 할 수 있습니다 (즉, 통화 스택을 검사하십시오).

편집 된 첫 번째 예제 (foo = function () {alert ( 'hello!');};), 해결되지 않은 과제이며, 항상 VAR 키워드를 사용하도록 권장합니다.

할당을 사용하면 VAR 문이 없으면 참조 된 식별자가 범위 체인에서 발견되지 않으면 전역 개체의 삭제 가능한 속성이됩니다.

또한 미확인 할당은 엄격한 모드에서 ECMAScript 5에서 ReferenceError를 던졌습니다.

A는 다음을 읽어야합니다.

명명 된 함수 표현식 Demystified.

참고 :이 답변은 OP의 주요 의심과 오해가 함수로 선언 된 식별자가 사용되지 않는 식별자가 그 식별자가 덮어 쓸 수 없었던 또 다른 질문에서 병합되었습니다.



답변

거의 모든 목적을 위해 게시 한 두 개의 코드 스 니펫은 같은 방식으로 행동합니다.

그러나, 동작의 차이점은 첫 번째 변형 (var functionOne = function () {})을 사용하여 해당 함수가 해당 코드가 해당 지점 이후 호출 될 수 있다는 것입니다.

두 번째 변형 (함수 functionTwo ())을 사용하면 기능이 선언 된 위치에서 위의 실행되는 코드 에서이 기능을 사용할 수 있습니다.

이는 첫 번째 변형이 있으므로 함수는 런타임에 변수 foo에 할당되기 때문입니다.두 번째 로이 기능은 파싱 시간에 해당 식별자 인 foo에 할당됩니다.

더 많은 기술 정보

JavaScript는 기능을 정의하는 세 가지 방법이 있습니다.

  1. Your first snippet shows a function expression. This involves using the "function" operator to create a function - the result of that operator can be stored in any variable or object property. The function expression is powerful that way. The function expression is often called an "anonymous function", because it does not have to have a name,
  2. Your second example is a function declaration. This uses the "function" statement to create a function. The function is made available at parse time and can be called anywhere in that scope. You can still store it in a variable or object property later.
  3. The third way of defining a function is the "Function()" constructor, which is not shown in your original post. It's not recommended to use this as it works the same way as eval(), which has its problems.


답변

Greg의 답변에 대한 더 나은 설명

functionTwo();
function functionTwo() {
}

왜 오류가 없습니까?우리는 표현이 상단에서 바닥에서 처형된다는 것을 항상 가르쳤습니다 (??)

때문에:

기능 선언 및 변수 선언은 항상 JavaScript 인터프리터에 의해 포함 된 범위 맨 위에 있음에 따라 항상 이동 (호이스트)됩니다.함수 매개 변수 및 언어 정의 이름은 분명히 이미 있습니다.벤 체리

즉,이 코드는 다음과 같은 코드를 의미합니다.

functionOne();                  ---------------      var functionOne;
                                | is actually |      functionOne();
var functionOne = function(){   | interpreted |-->
};                              |    like     |      functionOne = function(){
                                ---------------      };

선언문의 할당 부분이 호이스트되지 않았 음을 주목하십시오.이름 만 호이스트가됩니다.

그러나 기능 선언이있는 경우 전체 기능 본문은 또한 호이스트됩니다.

functionTwo();              ---------------      function functionTwo() {
                            | is actually |      };
function functionTwo() {    | interpreted |-->
}                           |    like     |      functionTwo();
                            ---------------
출처:https://stackoverflow.com/questions/336859/var-functionname-function-vs-function-functionname