var functionName = function () {} vs function functionName () {}


6871

최근에 다른 사람의 JavaScript 코드를 유지 관리하기 시작했습니다. 버그를 수정하고 기능을 추가하며 코드를 정리하고 일관성을 유지하려고합니다.

이전 개발자는 함수를 선언하는 두 가지 방법을 사용했으며 그 뒤에 이유가 있는지 알아낼 수 없습니다.

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

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

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


198
permadi.com/tutorial/jsFunc/index.html 은 자바 스크립트 함수에 관한 매우 좋은 페이지입니다
uzay95

67
명명 된 함수 표현식 에 대한 이 훌륭한 기사와 관련이 있습니다.
Phrogz

12
@CMS는이 기사를 참조한다 : kangax.github.com/nfe/#expr-vs-decl
Upperstage

106
알아야 할 두 가지 사항이 있습니다. # 1 JavaScript에서는 선언이 게양됩니다. 그 의미 var a = 1; var b = 2;var a; var b; a = 1; b = 2. 따라서 functionOne을 선언하면 선언되지만 값은 즉시 설정되지 않습니다. functionTwo는 단순한 선언이므로 범위의 맨 위에 배치됩니다. # 2 functionTwo를 사용하면 이름 속성에 액세스 할 수 있으며 무언가를 디버깅하려고 할 때 많은 도움이됩니다.
xavierm02

65
오, btw, 올바른 구문은 ";"입니다. 할당 후와 선언 후. 예 function f(){}var f = function(){};.
xavierm02

답변:


5043

차이점은 functionOne함수 표현식이므로 해당 줄에 도달했을 때만 정의되는 반면 functionTwo함수 선언이며 주변 함수 또는 스크립트가 실행 되 자마자 정의됩니다 ( 호이 스팅 으로 인해 ).

예를 들어 함수 표현식은 다음과 같습니다.

// TypeError: functionOne is not a function
functionOne();

var functionOne = function() {
  console.log("Hello!");
};

그리고 함수 선언 :

// Outputs: "Hello!"
functionTwo();

function functionTwo() {
  console.log("Hello!");
}

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

'use strict';    
{ // note this block!
  function functionThree() {
    console.log("Hello!");
  }
}
functionThree(); // ReferenceError


631
@ 그렉 : 그건 그렇고, 차이점은 그들이 다른 시간에 파싱된다는 것만이 아닙니다. 본질적으로, 귀하 functionOne는 익명 함수가 할당 된 변수 일 뿐이며 functionTwo실제로는 명명 된 함수입니다. .toString()차이점을 보려면 두 가지를 모두 호출 하십시오. 함수 적으로 프로그램 적으로 함수의 이름을 얻으려는 경우에 중요합니다.
Jason Bunting

6
@Jason Bunting .. 여기서 얻는 것이 확실하지 않은 경우 .toString ()은 본질적으로 동일한 값 (함수 정의)을 모두 반환하는 것으로 보입니다. cl.ly/2a2C2Y1r0J451o0q0B1B
Jon z

124
둘 다 다릅니다. 첫 번째 function expression는 두 번째는입니다 function declaration. 당신은 여기에 주제에 대한 자세한 내용을보실 수 있습니다 : javascriptweblog.wordpress.com/2010/07/06/...
마이클 Kuklis

127
@Greg 구문 분석 시간과 실행 시간에 대한 귀하의 답변의 일부가 올바르지 않습니다. JavaScript에서 함수 선언은 구문 분석 시간이 아니라 런타임 동안 정의됩니다. 프로세스는 다음과 같습니다. 소스 코드가 구문 분석됩니다-> JavaScript 프로그램이 평가됩니다-> 전역 실행 컨텍스트가 초기화됩니다-> 선언 바인딩 인스턴스화가 수행됩니다. 이 과정에서 함수 선언이 인스턴스화됩니다 ( 10.5 장의 5 단계 참조 ).
Šime Vidas

102
이 현상에 대한 용어를 게양이라고합니다.
Colin Pear

1941

먼저 Greg : function 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;

이 경우 둘 다 xyzabc같은 객체의 별칭입니다.

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

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

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);
  // ...
}

위의 예에서 외부 이름으로 동일한 작업을 수행 할 수 있지만 너무 다루기 힘들고 느립니다.

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

자바 스크립트는 두 문장을 다르게 취급합니다. 이것은 함수 선언입니다.

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

또한 return성명서를 통해 호이스트되었습니다 .

// 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

함수 선언과 함수 표현은 Greg에 의해 입증 된 차이점이있는 실제 이유입니다.

재미있는 사실:

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

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

var abc = function(){};

함수를 로컬로 정의했음을 알고 있습니다. 내가 함수를 정의 할 때

abc = function(){};

나는 abc범위 체인의 어느 곳에서도 정의하지 않았 음을 전 세계적으로 정의했음을 알고 있습니다. 이 스타일의 정의는 inside 내부에서도 사용될 수 있습니다 eval(). 정의하는 동안

function abc(){};

상황에 따라 달라지며 실제로 정의 된 위치, 특히 다음과 같은 경우에 추측 할 수 있습니다 eval(). 브라우저에 따라 다릅니다.


69
나는 RoBorg를 언급하지만 그는 어디에도 없다. 단순 : RoBorg === Greg. 인터넷 시대에 역사를 다시 쓸 수있는 방법입니다. ;-)
유진 라즈 킨

10
var xyz = 함수 abc () {}; console.log (xyz === abc); 내가 테스트 한 모든 브라우저 (Safari 4, Firefox 3.5.5, Opera 10.10)에 "정의되지 않은 변수 : abc"가 표시됩니다.
NVI

7
전반적 으로이 게시물은 함수 선언을 사용하는 것의 차이점과 장점을 설명하는 데 효과적입니다. 특히 "혜택"이 글로벌 엔티티를 선언하는 것을 촉구하는 것처럼 보이므로 함수 표현식 할당을 변수에 사용하면 얻을 수있는 이점에 동의하지 않을 것에 동의합니다. , 권리? ;-)
natlee75

83
imo 명명 된 함수를 사용해야하는 큰 이유는 디버거가이 이름을 사용하여 호출 스택 또는 스택 추적을 이해할 수 있기 때문입니다. 그것은 당신이 호출 스택을보고 10 수준 깊이 "익명 기능"을 볼 때 짜증 ...
염소

3
var abc = function(){}; console.log(abc.name);""더 이상 생산하지 않고 "abc"대신 생산 합니다 .
Qwerty

632

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

자귀:

빠른 목록 :

  • 함수 선언

  • "익명" function표현 (이 용어에도 불구하고 때때로 이름을 가진 함수를 생성 함)

  • 명명 된 function표현

  • 액세서 기능 이니셜 라이저 (ES5 +)

  • 화살표 함수 표현식 (ES2015 +) (익명 함수 표현식과 같이 명시적인 이름은 포함하지 않지만 이름을 가진 함수는 작성할 수 있음)

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

  • class(ES2015 +)의 생성자와 메소드 선언

함수 선언

첫 번째 형식은 다음과 같은 함수 선언입니다 .

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

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

함수 선언은 단계별 코드가 실행 되기 전에 실행이 표시되는 컨텍스트에 들어갈 때 처리됩니다 . 그것이 생성하는 함수는 적절한 이름 ( x위의 예에서 )으로 주어지며 , 그 이름은 선언이 나타나는 범위에 놓입니다.

동일한 컨텍스트에서 단계별 코드 전에 처리되기 때문에 다음과 같은 작업을 수행 할 수 있습니다.

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

ES2015까지 사양은 같은 제어 구조 안에 함수 선언을 넣을 경우 자바 스크립트 엔진이 무엇을해야 적용되지 않았다 try, if, switch, while같은, 등 :

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

또한 단계별 코드가 실행 되기 전에 처리되므로 제어 구조에있을 때 수행 할 작업을 아는 것이 까다 롭습니다.

이 작업은 ES2015까지 지정 되지 않았지만 블록에서 함수 선언을 지원 하는 확장이 가능 했습니다. 불행하게도 (그리고 필연적으로) 다른 엔진은 다른 일을했습니다.

ES2015 기준으로 사양에는 수행 할 작업이 나와 있습니다. 실제로 세 가지 별도의 작업을 수행합니다.

  1. 웹 브라우저가 아닌 느슨한 모드 인 경우 JavaScript 엔진은 한 가지 작업을 수행해야합니다.
  2. 웹 브라우저에서 느슨한 모드 인 경우 JavaScript 엔진은 다른 작업을 수행해야합니다
  3. 의 경우 엄격한 모드 (브라우저 또는하지 않음), 자바 스크립트 엔진은 또 다른 일을하도록되어

느슨한 모드에 대한 규칙은 까다 롭지 만 엄격 모드에서는 블록의 함수 선언이 쉽습니다. 블록에 대해 로컬 이며 (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)

"익명" function표현

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

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

모든 표현식과 마찬가지로 단계별 코드 실행에서 도달하면 평가됩니다.

ES5에서이 함수는 이름이 없습니다 (익명). ES2015에서는 가능한 경우 컨텍스트에서 유추하여 함수에 이름이 지정됩니다. 위의 예에서 이름은입니다 y. 함수가 속성 이니셜 라이저 값일 때 비슷한 작업이 수행됩니다. (이 상황과 규칙에 대한 자세한 내용 은 사양SetFunctionName 에서 검색 하십시오. 모든 곳에서  나타납니다 .)

명명 된 function표현

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

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

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

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

NFE는 종종 JavaScript 구현을위한 버그의 원인이되었습니다. 예를 들어 IE8 및 이전 버전에서는 NFE를 완전히 잘못 처리 하여 두 가지 다른 시간에 두 가지 다른 기능을 만듭니다. 초기 버전의 Safari에도 문제가있었습니다. 좋은 소식은 최신 버전의 브라우저 (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의 일이 숨어 map()전화를? 그것은 기능입니다.

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

  1. 그들에게는 자신의 것이 없습니다 this. 대신, 그들은 가까운 이상this 가 정의하고있는 문맥. (또한 닫고 arguments관련이있는 경우 super.) 이는 this내부 this가 작성 위치 와 동일 하며 변경할 수 없음을 의미합니다.

  2. 위에서 알 수 있듯이 키워드를 사용하지 않습니다 function. 대신을 사용 =>합니다.

n => n * 2위 의 예는 그중 하나입니다. 함수를 전달할 인수가 여러 개인 경우 parens를 사용합니다.

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

(즉 기억 Array#map첫 번째 인수로 진입하고, 상기 제로서 인덱스를 통과한다.)

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

단일 표현식 이상을 수행하는 경우 평소 {}와 같이 명시 적 return(값을 반환해야하는 경우)을 사용하십시오.

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));

없는 버전 { ... }표현식 본문 또는 간결한 본문이 있는 화살표 함수라고합니다 . (또한하십시오 간결한 . 화살표 기능)와 하나의 { ... }몸체를 형성은 A의 화살표 함수 기능 체 . (또한 : 자세한 화살표 기능)

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

ES2015는 메소드 정의 라는 함수를 참조하는 속성을 선언하는 짧은 형식을 허용합니다 . 다음과 같이 보입니다 :

var o = {
    foo() {
    }
};

ES5 및 그 이전 버전과 거의 동등한 내용은 다음과 같습니다.

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

(자세한 것 이외의) 차이점은 메소드가을 사용할 수 super있지만 함수는 사용할 수 없다는 것입니다. 예를 들어, valueOf메소드 구문을 사용하여 정의 된 객체가있는 경우 ES5 버전이 대신 수행해야하는 반면 super.valueOf()Object.prototype.valueOf을 반환 하는 데 사용할 수 있습니다 (아마도 다른 작업을 수행하기 전에) Object.prototype.valueOf.call(this).

즉, 메소드에 정의 된 오브젝트에 대한 참조가 메소드에 있음을 의미하므로 해당 오브젝트가 임시 인 경우 (예 : Object.assign소스 오브젝트 중 하나로 전달하는 경우 ) 메소드 구문 오브젝트가 유지됨을 의미 할 수 있습니다. 그렇지 않으면 메모리에 가비지 수집되었을 수 있습니다 (JavaScript 엔진이 해당 상황을 감지하지 않고 메소드를 사용하지 않는 경우 처리하지 않는 경우 super).

class(ES2015 +)의 생성자와 메소드 선언

ES2015는 class선언 된 생성자와 메소드를 포함한 구문을 제공 합니다 :

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

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

위에는 두 개의 함수 선언이 있습니다. 하나는 생성자를 Person위한 것이고 다른 하나 getFullName는에 할당 된 함수 Person.prototype입니다.


3
그 이름 w은 단순히 무시됩니까?
BiAiB

8
@PellePenna : 함수 이름은 많은 것들에 유용합니다. 필자의 관점에서 두 가지 큰 문제는 재귀와 호출 스택, 예외 추적 등에 표시되는 함수의 이름입니다.
TJ Crowder

4
@ChaimEliyah- "허용한다는 것이 정답이라는 의미는 아니며 요청한 사람에게 효과적이라는 의미입니다." 소스
ScrapCode

6
@AR : 사실입니다. 그러나 그 바로 위에는 "최고의 답변이 먼저 표시되므로 항상 쉽게 찾을 수 있습니다"라고되어 있습니다. 승인 된 답변은 투표율이 높은 답변보다 먼저 표시되므로 둘러보기가 다소 모순 될 수 있습니다. ;-) 또한 투표에서 "최고"를 결정하면 (정확하지 않은, 우리가 얻은 것임) "정확한"답변은 "투표"탭을 사용하는 경우에만 가장 먼저 표시됩니다. -그렇지 않으면 첫 번째 답변은 활성 답변이거나 가장 오래된 답변입니다.
TJ Crowder 2019

1
@TJCrowder : 동의합니다. '날짜로 정렬'은 때때로 성가신 일입니다.
ScrapCode

143

var명령문과 FunctionDeclaration끝에 있는 전역 컨텍스트에 대해 말하면 전역 오브젝트에 삭제할 수없는 특성 이 작성 되지만 둘 다의 값을 겹쳐 쓸 수 있습니다 .

두 가지 방법의 미묘한 차이점은 변수 인스턴스화 프로세스가 실행될 때 (실제 코드 실행 전에)로 선언 된 모든 식별자 var가로 초기화 undefined되고의 FunctionDeclaration순간에 사용 된 식별자는 다음 과 같이 사용 가능하다는 것입니다.

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

할당은 bar FunctionExpression런타임까지 수행됩니다.

FunctionDeclaration변수 값과 같은 문제없이 a로 만든 전역 속성을 덮어 쓸 수 있습니다. 예 :

 function test () {}
 test = null;

두 예제의 또 다른 명백한 차이점은 첫 번째 함수에는 이름이 없지만 두 번째 함수에는 이름이 있다는 점입니다. 이는 디버깅 할 때 실제로 유용 할 수 있습니다 (예 : 호출 스택 검사).

편집 한 첫 번째 예 ( foo = function() { alert('hello!'); };)에 대해서는 선언되지 않은 과제이므로 항상 var키워드를 사용하는 것이 좋습니다 .

var명령문이 없는 할당을 사용하면 범위 체인에서 참조 된 식별자를 찾을 수 없으면 전역 객체 의 삭제 가능한 속성이됩니다.

또한 선언되지 않은 할당 ReferenceError엄격 모드 아래 ECMAScript 5 에서을 발생 시킵니다.

반드시 읽어야합니다.

참고 :이 답변은 다른 질문 에서 병합되었습니다 . OP의 주요 의심과 오해는으로 선언 된 식별자를 FunctionDeclaration덮어 쓸 수 없다는 것입니다.


JavaScript로 함수를 덮어 쓸 수 있다는 것을 몰랐습니다! 또한 그 파싱 주문은 저에게 큰 판매 포인트입니다. 함수 생성 방법을 지켜봐야 할 것 같습니다.
Xeoncross

2
"404 함수"인 "이름 함수 표현식 미신"기사에 +0. 가능한 거울? : kangax.github.com/nfe
Mr_Chimp

@ CMS 좋은 하나입니다. 나는 원본을 보지 못했지만 명심하십시오. 그래서 그것이 거울인지 또는 동일한 제목의 다른 기사인지는 알 수 없습니다!
Mr_Chimp

@Mr_Chimp 나는 그것이 확신합니다, thewaybackmachine은 크롤링 시간에 302를 얻었으며 리디렉션은 제공 한 링크에 있다고합니다.
John

123

거기에 게시 한 두 개의 코드 스 니펫은 거의 모든 목적으로 동일한 방식으로 작동합니다.

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

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

첫 번째 변형에서는 함수가 foo런타임에 변수 에 할당되기 때문입니다 . 두 번째로, 함수는 foo구문 분석시 해당 식별자에 할당됩니다 .

더 많은 기술 정보

JavaScript에는 함수를 정의하는 세 가지 방법이 있습니다.

  1. 첫 번째 스 니펫은 함수 표현식을 보여줍니다 . 여기에는 "함수"연산자 를 사용하여 함수를 만드는 과정이 포함됩니다. 해당 연산자의 결과는 모든 변수 또는 객체 속성에 저장할 수 있습니다. 함수 표현식은 그렇게 강력합니다. 함수 표현식은 이름을 가질 필요가 없기 때문에 종종 "익명 함수"라고합니다.
  2. 두 번째 예는 함수 선언 입니다. 이것은 "function"문 을 사용하여 함수를 만듭니다. 이 함수는 구문 분석시 사용 가능하며 해당 범위의 어느 곳에서나 호출 할 수 있습니다. 나중에 변수 또는 객체 속성에 저장할 수 있습니다.
  3. 함수를 정의하는 세 번째 방법은 "Function ()"생성자 이며 원래 게시물에는 표시되지 않습니다. eval()문제가 있는 것과 같은 방식으로 작동하므로 사용하지 않는 것이 좋습니다 .

103

그렉의 대답에 대한 더 나은 설명

functionTwo();
function functionTwo() {
}

왜 오류가 없습니까? 우리는 항상식이 위에서 아래로 실행된다는 것을 배웠습니다 (??)

때문에:

함수 선언과 변수 선언은 hoistedJavaScript 인터프리터에 의해 항상 포함 범위의 맨 위로 이동합니다 ( ). 함수 매개 변수와 언어 정의 이름은 이미 존재합니다. 벤 체리

이것은 다음과 같은 코드를 의미합니다.

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

선언의 할당 부분은 게양되지 않았습니다. 이름 만 게양됩니다.

그러나 함수 선언의 경우 전체 함수 본문도 함께 게양됩니다 .

functionTwo();              ---------------      function functionTwo() {
                            | is actually |      };
function functionTwo() {    | interpreted |-->
}                           |    like     |      functionTwo();
                            ---------------

기능 주제에 대한 명확한 정보를 주셔서 감사합니다. 이제 내 질문은 변수 선언 (functionOne) 또는 함수 선언 (functionTwo) 여부에 관계없이 선언 계층 구조에서 첫 번째 선언은 무엇입니까?
Sharathi RB

91

다른 의견 제시 자들은 이미 위 두 변형의 의미 론적 차이를 다루었습니다. 스타일 차이를 언급하고 싶었습니다. "할당"변형 만 다른 개체의 속성을 설정할 수 있습니다.

나는 종종 다음과 같은 패턴으로 JavaScript 모듈을 빌드합니다.

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

    exports.publicUtil = function() {
            ...
    };

    return exports;
})();

이 패턴을 사용하면 공용 함수는 모두 할당을 사용하고 개인 함수는 선언을 사용합니다.

(선언에서는 선언이 금지하는 반면, 할당에는 명령문 뒤에 세미콜론이 필요합니다.)


4
yuiblog.com/blog/2007/06/12/module-pattern 은 내가 알 수있는 한 모듈 패턴의 기본 참조입니다. (이 기사에서는 var foo = function(){...}개인 변수에도 구문을 사용합니다 .
Sean McMillan

실제로 일부 IE 이전 버전에서는 이것이 사실이 아닙니다. ( function window.onload() {}일이었다.)
Ry-

77

첫 번째 방법을 두 번째 방법보다 선호하는시기는 함수의 이전 정의를 무시하지 않아야 할 때를 보여줍니다.

if (condition){
    function myfunction(){
        // Some code
    }
}

이 정의는 myfunction구문 분석시 수행되므로 이전 정의보다 우선합니다.

동안

if (condition){
    var myfunction = function (){
        // Some code
    }
}

충족 myfunction될 때만 정의하는 올바른 작업을 수행합니다 condition.


1
이 예는 좋고 완벽에 가깝지만 개선 될 수 있습니다. 더 나은 예는 var myFunc = null;루프 외부 또는 if / elseif / else 블록 외부에 정의 하는 것입니다. 그런 다음 동일한 변수에 다른 기능을 조건부로 할당 할 수 있습니다. JS에서는 결 측값을 null에 할당 한 다음 undefined에 할당하는 것이 더 좋습니다. 따라서 myFunction을 먼저 null로 선언 한 다음 나중에 조건부로 지정해야합니다.
Alexander Mills

62

중요한 이유는 네임 스페이스의 "루트"로 하나의 변수 만 추가하는 것입니다.

var MyNamespace = {}
MyNamespace.foo= function() {

}

또는

var MyNamespace = {
  foo: function() {
  },
  ...
}

네임 스페이스 기술에는 여러 가지가 있습니다. 사용 가능한 많은 JavaScript 모듈이 점점 중요 해지고 있습니다.

JavaScript로 네임 스페이스를 선언하는 방법을 참조하십시오 .


3
이 답변이 다른 질문 에서이 질문에 병합 된 것으로 보이며 문구 질문 과 관련 없는 것처럼 보일 수 있습니다 . 이 질문에 대한 답변이보다 구체적으로 표시되도록 답변 수정을 고려 하시겠습니까? (반복하기 위해; 이것은 당신의 잘못이 아니며 병합 된 질문의 부작용 일뿐입니다). 당신은 또한 그것을 삭제할 수 있으며, 나는 당신이 명성을 유지할 것이라고 생각합니다. 또는 당신은 그것을 떠날 수 있습니다; 오래되었으므로 큰 차이가 없을 수 있습니다.
Andrew Barber

55

호이 스팅 은 모든 변수 및 함수 선언을 현재 범위의 맨 위로 이동하는 JavaScript 해석기의 동작입니다.

그러나 실제 선언 만 게양됩니다. 할당 된 위치를 그대로 둡니다.

  • 페이지 내에서 선언 된 변수 / 함수는 전역 적으로 해당 페이지의 모든 위치에 액세스 할 수 있습니다.
  • 함수 내에서 선언 된 변수 / 함수에는 로컬 범위가 있습니다. 기능 본체 (범위) 내에서 사용 가능 / 액세스 할 수 있으며 기능 본체 외부에서는 사용할 수 없습니다.

변하기 쉬운

자바 스크립트를 느슨하게 입력 한 언어라고합니다. 이는 Javascript 변수가 모든 Data-Type 값을 보유 할 수 있음을 의미 합니다. Javascript는 런타임 동안 제공된 값 / 리터럴에 따라 변수 유형을 자동으로 관리합니다.

global_Page = 10;                                               var global_Page;      « undefined
    « Integer literal, Number Type.   -------------------       global_Page = 10;     « Number         
global_Page = 'Yash';                 |   Interpreted   |       global_Page = 'Yash'; « String
    « String literal, String Type.    «       AS        «       global_Page = true;   « Boolean 
var global_Page = true;               |                 |       global_Page = function (){          « function
    « Boolean Type                    -------------------                 var local_functionblock;  « undefined
global_Page = function (){                                                local_functionblock = 777 Number
    var local_functionblock = 777;                              };  
    // Assigning function as a data.
};  

함수

function Identifier_opt ( FormalParameterList_opt ) { 
      FunctionBody | sequence of statements

      « return;  Default undefined
      « return 'some data';
}
  • 페이지 내부에 선언 된 함수는 전역 액세스 권한이있는 페이지의 맨 위에 올립니다.
  • 펑션 블록 내부에 선언 된 함수는 블록 상단에 들어갑니다.
  • 함수의 기본 반환 값은 ' undefined ', 변수 선언 기본값은 'undefined'

    Scope with respect to function-block global. 
    Scope with respect to page undefined | not available.

함수 선언

function globalAccess() {                                  function globalAccess() {      
}                                  -------------------     }
globalAccess();                    |                 |     function globalAccess() { « Re-Defined / overridden.
localAccess();                     «   Hoisted  As   «         function localAccess() {
function globalAccess() {          |                 |         }
     localAccess();                -------------------         localAccess(); « function accessed with in globalAccess() only.
     function localAccess() {                              }
     }                                                     globalAccess();
}                                                          localAccess(); « ReferenceError as the function is not defined

함수 표현

        10;                 « literal
       (10);                « Expression                (10).toString() -> '10'
var a;                      
    a = 10;                 « Expression var              a.toString()  -> '10'
(function invoke() {        « Expression Function
 console.log('Self Invoking');                      (function () {
});                                                               }) () -> 'Self Invoking'

var f; 
    f = function (){        « Expression var Function
    console.log('var Function');                                   f ()  -> 'var Function'
    };

변수에 지정된 기능 예 :

(function selfExecuting(){
    console.log('IIFE - Immediately-Invoked Function Expression');
}());

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

var namedExpression = function for_InternalUSE(fact){
    if(fact === 1){
        return 1;
    }

    var localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    //return; //undefined.
    return fact * for_InternalUSE( fact - 1);   
};

namedExpression();
globalExpression();

자바 스크립트로 해석

var anonymous;
var namedExpression;
var globalExpression;

anonymous = function (){
    console.log('anonymous function Expression');
};

namedExpression = function for_InternalUSE(fact){
    var localExpression;

    if(fact === 1){
        return 1;
    }
    localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    return fact * for_InternalUSE( fact - 1);    // DEFAULT UNDEFINED.
};

namedExpression(10);
globalExpression();

다른 브라우저를 사용하여 함수 선언, 표현식 테스트를 확인할 수 있습니다. jsperf Test Runner


ES5 생성자 함수 클래스 : Function.prototype.bind를 사용하여 생성 된 함수 객체

JavaScript는 함수를 일급 객체로 취급하므로 객체이므로 속성을 함수에 할당 할 수 있습니다.

function Shape(id) { // Function Declaration
    this.id = id;
};
    // Adding a prototyped method to a function.
    Shape.prototype.getID = function () {
        return this.id;
    };
    Shape.prototype.setID = function ( id ) {
        this.id = id;
    };

var expFn = Shape; // Function Expression

var funObj = new Shape( ); // Function Object
funObj.hasOwnProperty('prototype'); // false
funObj.setID( 10 );
console.log( funObj.getID() ); // 10

ES6 도입 화살표 함수 : 화살표 함수 표현식은 구문이 더 짧으며 메소드가 아닌 함수에 가장 적합하며 생성자로 사용할 수 없습니다.

ArrowFunction : ArrowParameters => ConciseBody.

const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
console.log( fn(2) ); // Even
console.log( fn(3) ); // Odd

3
아, 네 대답은 ... 모호하지 않니? 너무 많은 정보를 쓰고 쓰는 데는 +1이지만 잘 작성되었습니다.
Danish

40

다른 모든 사람들이 호이 스팅 부분을 철저히 다루었 기 때문에 내 자신의 답변을 추가하고 있습니다.

나는 오랫동안 어떤 방법이 더 좋은지 궁금해했으며 지금 http://jsperf.com 덕분에 나는 알고있다 :)

여기에 이미지 설명을 입력하십시오

함수 선언 이 더 빠르며 웹 개발에서 실제로 중요한 것은 무엇입니까? ;)


8
유지 관리가 대부분의 코드에서 가장 중요한 측면이라고 말하고 싶습니다. 성능이 중요하지만 대부분의 경우 IO는 함수를 정의하는 방식보다 더 큰 병목 현상이 발생할 수 있습니다. 그러나 얻을 수있는 모든 성능이 필요한 몇 가지 문제가 있으며이 경우 유용합니다. 여기에 명확하게 정의 된 질문 부분에 대한 답변이있는 것도 좋습니다.
Richard Garside

3
글쎄, 나는 Firefox와 다른 방법으로 발견했다. jsperf.com/sandytest
Sandeep Nayak

이제는 JavaScript로 전체 기능 프로그래밍 스타일을 사용했기 때문에 선언을 사용하지 않고 함수 표현식 만 사용하므로 변수 이름으로 함수를 연결하고 호출 할 수 있습니다. ... RamdaJS 체크 아웃
레온 Gaban에게

1
@ SandeepNayak Firefox 50.0.0 / Windows 7 0.0.0에서 자체 테스트를 실행했으며 실제로 Leon과 동일한 방식입니다. 따라서 테스트가 정확하다면 jsperf의 테스트가 지시가 아니며 결론은 브라우저 및 / 또는 OS 버전 또는 특정 순간의 현재 시스템의 특정 상태에 따라 다릅니다.
ocramot

33

변수에 지정된 함수 선언과 함수 표현식은 바인딩이 설정되면 동일하게 동작합니다.

그러나 함수 객체가 실제로 변수와 연결 되는 방법시기 에는 차이가 있습니다 . 이 차이점은 JavaScript에서 변수 게양 이라는 메커니즘 때문 입니다.

기본적으로 모든 함수 선언과 변수 선언은 선언이 발생 하는 함수 의 최상위에 게양됩니다 (이 때문에 JavaScript에 함수 범위 가 있다고합니다 ).

  • 함수 선언이 들어 올릴 때 함수 본문이 "따라 오므로"함수 본문이 평가 될 때 변수는 즉시 함수 객체에 바인딩됩니다.

  • 변수 선언이 호이스트되면 초기화가 수행 되지 않지만 "뒤에 남습니다". 변수는 undefined함수 본문의 시작 부분으로 초기화되며 코드의 원래 위치에 값 이 할당됩니다 . (실제로 동일한 이름의 변수 선언이 발생하는 모든 위치에 값이 할당 됩니다.)

리프팅 순서도 중요합니다. 함수 선언은 이름이 같은 변수 선언보다 우선하고 마지막 함수 선언은 이름이 같은 이전 함수 선언보다 우선합니다.

몇 가지 예 ...

var foo = 1;
function bar() {
  if (!foo) {
    var foo = 10 }
  return foo; }
bar() // 10

변수 foo로 초기화하는 기능,의 상단에 게양되고 undefined그 때문에, !foo이다 true, 그래서 foo할당됩니다 10. foo외부 bar의 범위는 아무런 역할을하지 않고 그대로입니다.

function f() {
  return a; 
  function a() {return 1}; 
  var a = 4;
  function a() {return 2}}
f()() // 2

function f() {
  return a;
  var a = 4;
  function a() {return 1};
  function a() {return 2}}
f()() // 2

함수 선언은 변수 선언과 마지막 함수 선언 "sticks"보다 우선합니다.

function f() {
  var a = 4;
  function a() {return 1}; 
  function a() {return 2}; 
  return a; }
f() // 4

이 예제에서는 a두 번째 함수 선언을 평가 한 결과 함수 객체로 초기화 된 후 할당됩니다 4.

var a = 1;
function b() {
  a = 10;
  return;
  function a() {}}
b();
a // 1

여기서 함수 선언은 먼저 변수를 선언하고 초기화합니다 a. 다음으로이 변수가 할당됩니다 10. 즉, 할당이 외부 변수에 할당되지 않습니다 a.


3
닫는 괄호를 배치하는 약간 이상한 방법이 있습니다. 당신은 파이썬 코더입니까? Javascript를 Python처럼 보이게하려고하는 것 같습니다. 나는 그것이 다른 사람들에게 혼란스러워하는 것을 두려워합니다. JavaScript 코드를 유지해야한다면 먼저 자동 prettyprinter를 통해 코드를 보내도록하겠습니다.
nalply

1
훌륭한 게시물. '자기 실행 기능'또는 '즉시 호출 된 함수 표현식'은 쉽게 볼 수 있어야하며 스타일 선호도는 그의 게시물에서 벗어나지 않아야합니다. 정확하고 '게양'을 완벽하게 요약합니다. +1
Ricalsin

32

첫 번째 예는 함수 선언입니다.

function abc(){}

두 번째 예는 함수 표현식입니다.

var abc = function() {};

가장 큰 차이점은 어떻게 들어 올리는가입니다. 첫 번째 예에서는 전체 함수 선언이 들어 있습니다. 두 번째 예에서는 var 'abc'만 게양되고 값 (함수)이 정의되지 않으며 함수 자체는 선언 된 위치에 유지됩니다.

간단히 말해 :

//this will work
abc(param);
function abc(){}

//this would fail
abc(param);
var abc = function() {}

이 주제에 대해 더 연구하려면이 링크를 강력히 추천합니다


1
귀하의 예는 최고의 답변과 동일합니다
GôTô

이 답변을 게시 한 주된 이유는 맨 아래에 링크를 제공하기 위해서였습니다. 이것은 위의 질문을 완전히 이해하기 위해 누락 된 부분이었습니다.
sla55er 2016 년

1
링크를 공유하고 싶었던 것은 매우 멋진 일입니다. 그러나 추가 정보에 대한 링크는 질문이나 좋아하는 답변에 대한 의견이어야합니다. 마지막에 유용한 링크 하나를 추가하기 위해 반복되는 정보로 길고 복잡한 페이지를 복잡하게 만드는 것이 차선책입니다. 아니요, 링크 제공에 대한 담당자는 없지만 커뮤니티를 돕습니다.
XML

30

코드 유지 관리 비용 측면에서 명명 된 함수가 더 바람직합니다.

  • 그들이 선언 된 장소와는 독립적입니다 (그러나 여전히 범위에 의해 제한됩니다).
  • 조건부 초기화와 같은 실수에 더 강합니다 (원하는 경우 재정의 할 수 있음).
  • 범위 기능과 별도로 로컬 기능을 할당하여 코드를보다 쉽게 ​​읽을 수 있습니다. 일반적으로 범위 내에서 기능이 먼저 수행되고 그 다음에 로컬 함수가 선언됩니다.
  • 디버거에서는 "익명 / 평가 된"함수 대신 호출 스택에 함수 이름이 명확하게 표시됩니다.

명명 된 기능에 대한 더 많은 PROS가 따르는 것으로 생각됩니다. 그리고 명명 된 함수의 장점으로 나열된 것은 익명 함수의 단점입니다.

역사적으로 익명 함수는 JavaScript가 언어로 기능 할 수 없기 때문에 이름이 지정된 함수를 가진 멤버를 나열합니다.

{
    member:function() { /* How do I make "this.member" a named function? */
    }
}

2
: 확인에 시험이 있습니다 blog.firsov.net/2010/01/... 범위와 이름 지정된 함수 - - 분석 JS 성능 테스트
사샤 Firsov

25

컴퓨터 과학 용어로 익명 함수와 명명 된 함수에 대해 이야기합니다. 가장 중요한 차이점은 익명 함수가 이름에 바인딩되지 않으므로 이름이 익명 함수라는 것입니다. JavaScript에서는 런타임에 동적으로 선언 된 첫 번째 클래스 객체입니다.

익명 함수 및 람다 미적분에 대한 자세한 내용은 Wikipedia를 시작하는 것이 좋습니다 ( http://en.wikipedia.org/wiki/Anonymous_function ).


ES2015 기준 (답변이 게시 된 후 6 년 반)에 해당 질문의 두 기능이 모두 지정되었습니다.
TJ Crowder

25

나는 매우 구체적인 이유로 내 코드에서 변수 접근 방식을 사용하는데, 그 이론은 위의 추상적 인 방식으로 다루어졌지만 예제는 제한된 JavaScript 전문 지식으로 나와 같은 일부 사람들에게 도움이 될 수 있습니다.

160 개의 독립적으로 디자인 된 브랜딩으로 실행해야하는 코드가 있습니다. 코드의 대부분은 공유 파일에 있지만 브랜딩 관련 항목은 각 브랜딩마다 하나씩 별도의 파일에 있습니다.

일부 브랜드에는 특정 기능이 필요하지만 일부 브랜드에는 그렇지 않습니다. 때로는 새로운 브랜드 관련 일을하기 위해 새로운 기능을 추가해야합니다. 공유 코드를 변경해도 좋으나 160 개의 브랜딩 파일 세트를 모두 변경하고 싶지는 않습니다.

변수 구문을 사용하여 공유 코드에서 변수 (기본적으로 함수 포인터)를 선언하고 사소한 스텁 함수를 할당하거나 null로 설정할 수 있습니다.

함수의 특정 구현이 필요한 하나 또는 두 개의 브랜딩은 함수의 버전을 정의하고 원하는 경우 변수에 할당 할 수 있으며 나머지는 아무 것도하지 않습니다. 공유 코드에서 null 함수를 실행하기 전에 null 함수를 테스트 할 수 있습니다.

위의 사람들의 의견에서 정적 함수도 재정의하는 것이 가능할 수도 있지만 변수 솔루션이 훌륭하고 명확하다고 생각합니다.


25

Greg의 답변 은 충분하지만 지금 Douglas Crockford의 비디오를 보면서 배운 내용을 추가하고 싶습니다 .

함수 표현 :

var foo = function foo() {};

기능 설명 :

function foo() {};

함수 명령문은 값 var이있는 명령문 의 약어입니다 function.

그래서

function foo() {};

~로 확장

var foo = function foo() {};

다음으로 확장 :

var foo = undefined;
foo = function foo() {};

그리고 그들은 모두 코드 상단에 올라 있습니다.

비디오 스크린 샷


7
미안하지만 이것은 틀 렸습니다-Crockford가 그 슬라이드에서 무엇을 말하려고하는지 모르겠습니다. 함수 및 변수 선언은 항상 해당 범위의 맨 위로 호이스트됩니다. 차이점은 변수 할당 (문자열, 부울 또는 함수로 할당 여부)이 맨 위로 올라가지 않는 반면 함수 본문 (함수 선언 사용)은 다릅니다.
Thomas Heymann

다음 코드 예제를 살펴보십시오. gist.github.com/cyberthom/36603fbc20de8e04fd09
Thomas Heymann

23

아래에 나열된 두 가지 함수 선언 간에는 네 가지 주목할만한 비교가 있습니다.

  1. 기능의 가용성 (범위)

function add()가장 가까운 블록 범위에 있기 때문에 다음과 같이 작동합니다 .

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

function add(a, b){
  return a + b;
}

함수 값이 변수에 할당되기 전에 변수가 호출되므로 다음은 작동하지 않습니다 add.

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function(a, b){
  return a + b;
}

위 코드는 기능면에서 아래 코드와 동일합니다. 명시 적으로 할당하는 add = undefined것은 단순히 불필요한 일과 var add;동일 하기 때문에 불필요 var add=undefined합니다.

var add = undefined;

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

add = function(a, b){
  return a + b;
}

다음을 var add=대체 하기 때문에 작동하지 않습니다 function add().

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function add(a, b){
  return a + b;
}

  1. (기능) .name

이 방법으로 선언 될 때 함수의 이름 function thefuncname(){}funcname 입니다.

function foobar(a, b){}

console.log(foobar.name);

var a = function foobar(){};

console.log(a.name);

그렇지 않으면 함수가로 선언 function(){}되면 함수 .name은 함수 를 저장하는 데 사용되는 첫 번째 변수입니다.

var a = function(){};
var b = (function(){ return function(){} });

console.log(a.name);
console.log(b.name);

함수에 변수가 설정되어 있지 않으면 함수 이름은 빈 문자열 ( "")입니다.

console.log((function(){}).name === "");

마지막으로 함수에 할당 된 변수는 처음에 이름을 설정하지만 함수에 설정된 연속 변수는 이름을 변경하지 않습니다.

var a = function(){};
var b = a;
var c = b;

console.log(a.name);
console.log(b.name);
console.log(c.name);

  1. 공연

Google의 V8과 Firefox의 Spidermonkey에는 약간의 마이크로 초 JIST 컴파일 차이가있을 수 있지만 결과는 동일합니다. 이를 증명하기 위해 두 개의 빈 코드 스 니펫의 속도를 비교하여 마이크로 벤치 마크에서 JSPerf의 효율성을 살펴 보겠습니다. JSPerf 테스트는 여기에서 발견된다 . 그리고 jsben.ch 테스트는 여기에 있습니다 . 보시다시피, 아무것도 없어야 할 때 눈에 띄는 차이가 있습니다. 당신이 정말로 나 같은 성능 괴물이라면, 범위에서 변수와 함수의 수를 줄이고 특히 다형성을 제거하려고 시도하는 동안 (예를 들어 두 개의 다른 유형을 저장하기 위해 같은 변수를 사용하는) 더 가치가있을 수 있습니다.

  1. 가변 돌연변이 성

var키워드를 사용하여 변수를 선언하면 다른 값을 변수에 다시 지정할 수 있습니다.

(function(){
    "use strict";
    var foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

그러나 const 문을 사용하면 변수 참조가 변경되지 않습니다. 이것은 변수에 새로운 값을 할당 할 수 없다는 것을 의미합니다. 그러나 이로 인해 변수의 내용을 변경할 const arr = []수는 없습니다 arr[10] = "example". 그렇게해도 여전히 할 수 있습니다 . 아래와 같이 뭔가를 arr = "new value"하거나 arr = []오류가 발생합니다.

(function(){
    "use strict";
    const foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

흥미롭게도 변수를로 선언하면 변수 function funcName(){}의 불변성은 변수를로 선언하는 것과 같습니다 var.

(function(){
    "use strict";
    function foobar(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

"가장 가까운 블록"이란 무엇입니까

"가장 가까운 블록"은 가장 가까운 "기능"입니다 (비동기 기능, 생성기 기능 및 비동기 생성기 기능 포함). 그러나, 흥미롭게도, 폐쇄가 아닌 블록에있을 때 상기 폐쇄 외부의 아이템들 function functionName() {}과 같은 행동을한다 var functionName = function() {}. 관찰하십시오.

  • 표준 var add=function(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}');
  }
} catch(e) {
  console.log("Is a block");
}
var add=function(a, b){return a + b}

  • 표준 function add(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
function add(a, b){
  return a + b;
}

  • 함수

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(function () {
    function add(a, b){
      return a + b;
    }
})();

  • 정책 (예컨대 if, else, for, while, try/ catch/ finally, switch, do/ while, with)

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
{
    function add(a, b){
      return a + b;
    }
}

  • 화살표 기능 var add=function()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    var add=function(a, b){
      return a + b;
    }
})();

  • 화살표 기능 function add()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    function add(a, b){
      return a + b;
    }
})();


이것은 인정되고 가장 찬란한 답변이 될 만하다
Aaron John Sabu

18

@EugeneLazutkin 은 자신에게 내부 참조로 사용할 수 있도록 할당 된 함수의 이름을 지정shortcut() 하는 예를 제공 합니다. John ResigLearning Advanced Javascript tutorial 에서 다른 객체지정된 재귀 함수를 복사하는 또 다른 예를 제공합니다 . 속성에 함수를 할당하는 것이 여기서 중요한 것은 아니지만 튜토리얼을 적극적으로 시도하는 것이 좋습니다. 오른쪽 상단에있는 버튼을 클릭하여 코드를 실행하고 코드를 두 번 클릭하여 원하는대로 편집하십시오.

학습서의 예제 : 재귀 호출 yell():

원래 닌자 개체를 제거하면 테스트가 실패합니다. (13 페이지)

var ninja = { 
  yell: function(n){ 
    return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); 

var samurai = { yell: ninja.yell }; 
var ninja = null; 

try { 
  samurai.yell(4); 
} catch(e){ 
  assert( false, "Uh, this isn't good! Where'd ninja.yell go?" ); 
}

재귀 적으로 호출 될 함수의 이름을 지정하면 테스트가 통과됩니다. (14 페이지)

var ninja = { 
  yell: function yell(n){ 
    return n > 0 ? yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" ); 

var samurai = { yell: ninja.yell }; 
var ninja = {}; 
assert( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." );

17

다른 답변에서 언급되지 않은 또 다른 차이점은 익명 함수를 사용하면

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

에서와 같이 생성자로 사용하십시오.

var one = new functionOne();

다음 one.constructor.name정의되지 않습니다. Function.name비표준이지만 Firefox, Chrome, 기타 웹킷 파생 브라우저 및 IE 9 이상에서 지원됩니다.

function functionTwo() {
    // Some code
}
two = new functionTwo();

로 생성자의 이름을 문자열로 검색 할 수 있습니다 two.constructor.name.


첫 번째 경우의 이름은 변수에 할당 된 익명 함수 이므로 정의되지 않습니다 . 익명이라는 단어는 이름이 정의되지 않은 것들을 위해 발명되었다고 생각합니다.)
Om Shankar

이 예제에서 2 = new는 전역 함수가됩니다. var
Waqas Tahir

16

첫 번째 것 (함수 doSomething (x))은 객체 표기법의 일부 여야합니다.

두 번째 ( var doSomething = function(x){ alert(x);})는 단순히 익명 함수를 만들어 변수에 할당하는 것 doSomething입니다. 따라서 doSomething ()은 함수를 호출합니다.

함수 선언함수 표현식 이 무엇인지 알고 싶을 수도 있습니다 .

함수 선언은 변수 할당없이 명명 된 함수 변수를 정의합니다. 함수 선언은 독립형 구조로 발생하며 비 기능 블록 내에 중첩 될 수 없습니다.

function foo() {
    return 3;
}

ECMA 5 (13.0)는 구문을
함수 식별자 (FormalParameterList opt ) {FunctionBody} 로 정의합니다.

위의 조건에서 함수 이름은 해당 범위와 상위 범위 내에 표시됩니다 (그렇지 않으면 도달 할 수 없음).

그리고 함수 표현에서

함수 표현식은 함수를 더 큰 표현식 구문의 일부로 정의합니다 (일반적으로 변수 할당). 함수 표현식을 통해 정의 된 함수는 이름을 지정하거나 익명으로 지정할 수 있습니다. 함수 표현식은 "function"으로 시작하지 않아야합니다.

// Anonymous function expression
var a = function() {
    return 3;
}

// Named function expression
var a = function foo() {
    return 3;
}

// Self-invoking function expression
(function foo() {
    alert("hello!");
})();

ECMA 5 (13.0)는 구문을
함수 식별자 opt (FormalParameterList opt ) {FunctionBody}


16

아래 차이점을 나열하고 있습니다.

  1. 함수 선언은 코드의 어느 곳에 나 배치 할 수 있습니다. 정의가 코드에 나타나기 전에 호출 되더라도 함수 선언이 메모리에 커밋되거나 페이지의 다른 코드가 실행되기 전에 게양되는 방식으로 실행됩니다.

    아래 기능을 살펴보십시오.

    function outerFunction() {
        function foo() {
           return 1;
        }
        return foo();
        function foo() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 2

    실행하는 동안 다음과 같이 보이기 때문입니다.

    function foo() {  // The first function declaration is moved to top
        return 1;
    }
    function foo() {  // The second function declaration is moved to top
        return 2;
    }
    function outerFunction() {
        return foo();
    }
    alert(outerFunction()); //So executing from top to bottom,
                            //the last foo() returns 2 which gets displayed

    함수 표현식을 호출하기 전에 정의하지 않으면 오류가 발생합니다. 또한 함수 정의 자체는 함수 선언과 같이 맨 위로 이동하거나 메모리에 커밋되지 않습니다. 그러나 함수를 할당하는 변수가 올라가고 정의되지 않은 함수 가 할당됩니다.

    함수 표현식을 사용하는 동일한 함수 :

    function outerFunction() {
        var foo = function() {
           return 1;
        }
        return foo();
        var foo = function() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 1

    실행하는 동안 다음과 같이 보이기 때문입니다.

    function outerFunction() {
       var foo = undefined;
       var foo = undefined;
    
       foo = function() {
          return 1;
       };
       return foo ();
       foo = function() {   // This function expression is not reachable
          return 2;
       };
    }
    alert(outerFunction()); // Displays 1
  2. 이 같은 비 기능 블록에서 함수 선언을 쓸 안전하지 않습니다 경우 가 액세스 할 수 없습니다 때문입니다.

    if (test) {
        function x() { doSomething(); }
    }
  3. 아래와 같은 명명 된 함수 표현식은 버전 9 이전의 Internet Explorer 브라우저에서 작동하지 않을 수 있습니다.

    var today = function today() {return new Date()}

1
@Arjun 몇 년 전에 질문을했을 경우 어떤 문제가 있습니까? 답변은 언제 질문을 받더라도 OP뿐 아니라 모든 SO 사용자에게도 도움이됩니다. 그리고 이미 받아 들여진 대답이있는 질문에 답하는 것은 무엇이 문제입니까?
SantiBailors

1
@Arjun은 오래된 질문에 대답하는 것이 나쁘지 않습니다. 만약 그렇다면 SO는 그런 장벽을 가지고 있었을 것입니다. API에 변경 사항이 있지만 (이 질문의 맥락에 있지는 않지만) 누군가 API를 발견하고 새 API에 대한 답변을 제공한다고 상상해보십시오. 대답이 의미가없고 여기에 속하지 않을 때까지는 대답이 자동으로 내려져 제거됩니다. 당신은 그것을 귀찮게 할 필요가 없습니다 !!!!
Sudhansu Choudhary

15

이러한 함수를 사용하여 객체를 만들면 다음과 같은 이점이 있습니다.

var objectOne = new functionOne();
console.log(objectOne.__proto__); // prints "Object {}" because constructor is an anonymous function

var objectTwo = new functionTwo();
console.log(objectTwo.__proto__); // prints "functionTwo {}" because constructor is a named function

나는 이것을 재현 할 수 없다. console.log(objectOne.__proto__);콘솔에 "functionOne {}"을 인쇄합니다. 이것이 왜 그런지에 대한 아이디어가 있습니까?
Mike

나는 그것을 재현 할 수없는 것 같습니다.
daremkd

1
이것은 디버거의 기능이며 (로그 된 객체의 "클래스"를 표시하기 위해) 요즘 익명 함수 표현식에 대해서도 이름을 도출 할 수 있습니다. Btw, 두 인스턴스간에 기능적 차이가 없음을 분명히해야합니다.
Bergi

12

"명명 된 함수는 스택 트레이스에 표시"라는 주장에 비추어 현대 JavaScript 엔진은 실제로 익명 함수를 나타낼 수 있습니다.

이 글을 쓰는 시점에서 V8, SpiderMonkey, Chakra 및 Nitro는 항상 이름으로 명명 된 기능을 참조합니다. 익명 함수는 식별자가있는 경우 항상 익명 함수를 참조합니다.

SpiderMonkey는 다른 함수에서 반환 된 익명 함수의 이름을 알아낼 수 있습니다. 나머지는 할 수 없습니다.

정말로 반복자와 성공 콜백이 트레이스에 나타나기를 원한다면 이름도 지정할 수 있습니다 ...

[].forEach(function iterator() {});

그러나 대부분 스트레스를받을 가치가 없습니다.

하네스 ( 피들 )

'use strict';

var a = function () {
    throw new Error();
},
    b = function b() {
        throw new Error();
    },
    c = function d() {
        throw new Error();
    },
    e = {
        f: a,
        g: b,
        h: c,
        i: function () {
            throw new Error();
        },
        j: function j() {
            throw new Error();
        },
        k: function l() {
            throw new Error();
        }
    },
    m = (function () {
        return function () {
            throw new Error();
        };
    }()),
    n = (function () {
        return function n() {
            throw new Error();
        };
    }()),
    o = (function () {
        return function p() {
            throw new Error();
        };
    }());

console.log([a, b, c].concat(Object.keys(e).reduce(function (values, key) {
    return values.concat(e[key]);
}, [])).concat([m, n, o]).reduce(function (logs, func) {

    try {
        func();
    } catch (error) {
        return logs.concat('func.name: ' + func.name + '\n' +
                           'Trace:\n' +
                           error.stack);
        // Need to manually log the error object in Nitro.
    }

}, []).join('\n\n'));

V8

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at e.i (http://localhost:8000/test.js:17:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: j
Trace:
Error
    at j (http://localhost:8000/test.js:20:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: l
Trace:
Error
    at l (http://localhost:8000/test.js:23:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at http://localhost:8000/test.js:28:19
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: n
Trace:
Error
    at n (http://localhost:8000/test.js:33:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: p
Trace:
Error
    at p (http://localhost:8000/test.js:38:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27 test.js:42

거미 원숭이

func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
e.i@http://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: j
Trace:
j@http://localhost:8000/test.js:20:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: l
Trace:
l@http://localhost:8000/test.js:23:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
m</<@http://localhost:8000/test.js:28:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: n
Trace:
n@http://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: p
Trace:
p@http://localhost:8000/test.js:38:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1

차크라

func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at e.i (http://localhost:8000/test.js:17:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at j (http://localhost:8000/test.js:20:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at l (http://localhost:8000/test.js:23:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at Anonymous function (http://localhost:8000/test.js:28:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at n (http://localhost:8000/test.js:33:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at p (http://localhost:8000/test.js:38:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)

니트로

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
i@http://localhost:8000/test.js:17:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: j
Trace:
j@http://localhost:8000/test.js:20:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: l
Trace:
l@http://localhost:8000/test.js:23:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
http://localhost:8000/test.js:28:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: n
Trace:
n@http://localhost:8000/test.js:33:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: p
Trace:
p@http://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

12

JavaScript에는 함수를 작성하는 두 가지 방법이 있습니다.

  1. 함수 선언 :

    function fn(){
      console.log("Hello");
    }
    fn();

    이것은 매우 기본적이고 자명하며 C 언어 군에 걸쳐 많은 언어와 표준으로 사용됩니다. 정의 된 함수를 선언하고 호출하여 실행했습니다.

    알아야 할 것은 함수는 실제로 JavaScript의 객체라는 것입니다. 내부적으로 우리는 위의 함수에 대한 객체를 만들고 이름을 fn이라고 지정하거나 객체에 대한 참조가 fn에 저장됩니다. 함수는 JavaScript의 객체입니다. 함수의 인스턴스는 실제로 객체 인스턴스입니다.

  2. 함수 표현 :

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

    JavaScript에는 일급 함수가 있습니다. 즉, 문자열이나 숫자를 만들어 변수에 할당하는 것처럼 함수를 만들어 변수에 할당합니다. 여기서 fn 변수는 함수에 할당됩니다. 이 개념의 이유는 함수가 JavaScript의 객체이기 때문입니다. fn은 위 함수의 객체 인스턴스를 가리 킵니다. 함수를 초기화하고 변수에 할당했습니다. 함수를 실행하지 않고 결과를 할당하지 않습니다.

참조 : JavaScript 함수 선언 구문 : var fn = function () {} vs function fn () {}


1
세 번째 옵션은 var fn = function fn() {...}어떻습니까?
chharvey

안녕하세요 Chharvey, ur 질문에 대해 잘 모르겠습니다. 이미 언급 한 함수 표현에 대해 이야기하는 것 같습니다. 그러나 여전히 혼란이 있다면 좀 더 정교합니다.
Anoop Rai

예, 명명 된 함수 표현식 에 대해 묻고있었습니다 . 함수에 식별자가 있다는 점을 제외하고는 옵션 # 2와 비슷합니다. 일반적으로이 식별자는 할당되는 변수와 동일하지만 항상 그런 것은 아닙니다.
chharvey

1
예 명명 된 함수 표현식은 옵션 # 2와 유사합니다. 식별자를 사용하는 것은 사용되지 않기 때문에 필수는 아닙니다. 함수 표현식을 실행할 때마다 함수 객체를 보유하는 변수를 사용합니다. 식별자는 목적이 없습니다.
Anoop Rai

11

둘 다 함수를 정의하는 다른 방법입니다. 차이점은 브라우저가이를 해석하고 실행 컨텍스트로로드하는 방법입니다.

첫 번째 경우는 인터프리터가 해당 코드 줄에 도달 할 때만로드되는 함수 표현식입니다. 따라서 다음과 같이하면 functionOne이 함수가 아니라는 오류가 발생합니다 .

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

그 이유는 첫 번째 행에서 functionOne에 값이 지정되지 않았으므로 정의되지 않기 때문입니다. 함수로 호출하려고하므로 오류가 발생합니다.

두 번째 줄에서는 익명 함수의 참조를 functionOne에 할당합니다.

두 번째 경우는 코드가 실행되기 전에로드되는 함수 선언입니다. 따라서 다음을 좋아하면 코드 실행 전에 선언이로드 될 때 오류가 발생하지 않습니다.

functionOne();
function functionOne() {
   // Some code
}

11

성능 정보 :

새 버전의 V8여러 가지 기본 최적화 가 도입되었습니다 SpiderMonkey.

표현과 선언 사이에는 거의 차이가 없습니다.
함수 표현 이 더 빠른 것 같습니다 졌습니다.

크롬 62.0.3202 크롬 테스트

파이어 폭스 55 Firefox 테스트

크롬 카나리아 63.0.3225 크롬 카나리아 테스트


Anonymous함수 표현식 Named 함수 표현식 에 비해 성능이 더 좋은 것으로 보입니다 .


Firefox Chrome 카나리아 ChromeFirefox named_anonymous Chrome 카나리아 named_anonymous 이름이 Chrome 인 익명


1
그렇습니다.이 차이는 매우 중요하지 않기 때문에 희망적으로 개발자는 어떤 접근 방식이 어떤 것이 더 빠르지 않고 특정 요구에 더 잘 유지 관리 가능한지에 관심을 가질 것입니다 (브라우저의 작업에 따라 각 시도마다 다른 jsperf 결과를 얻을 있습니다) 대부분의 자바 스크립트 작업은이 정도의 미세 최적화와 관련이 없습니다.
오징어

@squidbe 차이가 없습니다. 여기를보십시오 : jsperf.com/empty-tests-performance
Jack Giffin

10

그것들은 약간의 차이점과 꽤 비슷합니다. 첫 번째 변수는 익명 함수 (함수 선언)에 할당 된 변수이고 두 번째 변수는 JavaScript (익명 함수 선언)에서 함수를 만드는 일반적인 방법이며 사용법, 단점 및 장점이 있습니다 :

1. 함수 표현

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

함수 표현식은 함수를 더 큰 표현식 구문의 일부로 정의합니다 (일반적으로 변수 할당). 함수 표현식을 통해 정의 된 함수는 이름을 지정하거나 익명으로 지정할 수 있습니다. 함수 표현식은 "function"으로 시작해서는 안됩니다 (따라서 아래의 자체 호출 예제 주위의 괄호).

JavaScript에서 함수가 호이스트 할 수 있다는 것을 알고 있듯이 변수를 함수에 할당하면 호이 스팅이 없음을 의미합니다. 선언하기 전에 호출 할 수 있음을 의미합니다. 선언 된 위치에 함수에 액세스하십시오. 또한 함수를 작성하는 방법 일 수 있습니다. 다른 함수를 반환하는 함수의 경우 이러한 종류의 선언이 의미가 있습니다 .ECMA6 이상에서는 화살표 함수에 지정할 수 있습니다. 익명 함수를 호출하는 데 사용될 수 있으며, 이러한 선언 방법은 JavaScript에서 생성자 함수를 작성하는 더 좋은 방법입니다.

2. 함수 선언

function functionTwo() {
    // Some code
}

함수 선언은 변수 할당을 요구하지 않고 명명 된 함수 변수를 정의합니다. 함수 선언은 독립형 구조로 발생하며 비 기능 블록 내에 중첩 될 수 없습니다. 변수 선언의 형제로 생각하면 도움이됩니다. 변수 선언이 "var"로 시작해야하는 것처럼 함수 선언은 "function"으로 시작해야합니다.

이것은 JavaScript에서 함수를 호출하는 일반적인 방법입니다.이 함수는 JavaScript에서 모든 함수가 게양되는 것처럼 선언하기 전에 호출 할 수 있지만 '엄격한 사용'이 있으면 예상대로 호이스트하지 않는 것이 좋습니다. 줄이 크지 않고 생성자 함수가 아닌 모든 일반 함수를 호출합니다.

또한 JavaScript에서 호이 스팅이 작동하는 방식에 대한 자세한 정보가 필요하면 아래 링크를 방문하십시오.

https://developer.mozilla.org/en-US/docs/Glossary/Hoisting


1
...also this way of declaring is a better way to create Constructor functions in JavaScript궁금한 점이 있으십니까? 궁금합니다.
Karl Morrison

한 가지 이유는이 함수 Number () {[native code]}와 같이 JavaScript의 모든 내장 생성자 함수가 작성되었으므로 내장 함수와 혼동해서는 안되며,이 경우 나중에 참조하는 것이 더 안전하고 종료되기 때문입니다. 권상를 사용하지 않는 깔끔한 코드까지하지만 ...
알리레자

8

이것은 함수를 선언하는 두 가지 가능한 방법이며 두 번째 방법으로 선언 전에 함수를 사용할 수 있습니다.


7

new Function()함수 본문을 문자열로 전달하는 데 사용할 수 있습니다. 따라서 동적 기능을 만드는 데 사용할 수 있습니다. 또한 스크립트를 실행하지 않고 스크립트를 전달합니다.

var func = new Function("x", "y", "return x*y;");
function secondFunction(){
   var result;
   result = func(10,20);
   console.log ( result );
}

secondFunction()

이것이 좋고 사실이지만, 이것 만이 요청되는 질문과 정확히 어떻게 관련이 있습니까?
잭 지핀
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.