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

나는 최근에 다른 사람의 자바스크립트 코드를 관리하기 시작했다.버그를 수정하고, 기능을 추가하고, 코드를 정리하고, 일관성을 유지하려고 노력하고 있습니다.

이전 개발자는 두 가지 방법으로 함수를 선언했는데, 그 배경에 이유가 있는지 없는지는 알 수 없습니다.

다음 두 가지 방법이 있습니다.

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

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



질문에 대한 답변



다른 점은 말이다.functionOne는 함수식이며, 그 행에 도달했을 때만 정의됩니다.functionTwo는 함수 선언이며 주변 함수 또는 스크립트가 실행되자마자 정의됩니다(호이스트에 의해).

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

// TypeError: functionOne is not a function functionOne();
var functionOne = function() {
console.log("Hello!"); };

그리고 함수 선언:

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

과거에는 블록 내에 정의된 함수 선언이 브라우저 간에 일관되지 않게 처리되었습니다.strict 모드(ES5에서 도입)는 함수 선언을 둘러싸는 블록에 스코핑함으로써 이 문제를 해결했습니다.

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




먼저 Greg를 수정하고 싶습니다.function abc(){}scope 도 scope 됩니다.이름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);
// ... } 

위의 예에서는 외부 이름을 사용하여 동일한 작업을 수행할 수 있지만 너무 번거롭고 느립니다.

(그 자체를 가리키는 또 다른 방법은arguments.callee(이것은 아직 비교적 길고, 엄밀한 모드에서는 지원되지 않습니다).

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 

또한, 그것은 다음 중 하나를 통과했다.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스코프의 사슬의 어느 곳이든.이 스타일의 정의는 내부에서 사용하더라도 복원력이 있습니다.eval(). 정의와

function abc(){}; 

문맥에 따라 다르며, 특히 의 경우 실제로 정의되어 있는 장소를 추측하게 할 수 있습니다.eval()– 답은 다음과 같습니다.브라우저에 따라 다릅니다.




함수를 작성하는 표준 폼의 개요는 다음과 같습니다(원래는 다른 질문을 위해 작성되었지만, 정식 질문으로 이동한 후 수정되었습니다).

조건:

빠른 목록:

  • 함수 선언

  • “익명”function식(용어에도 불구하고 이름을 사용하여 함수를 만들 수 있음)

  • 이름 지어진function표현

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

  • Arrow Function Expression (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까지는 다음과 같은 제어 구조 내에 함수 선언을 넣는 경우 JavaScript 엔진이 무엇을 해야 하는지 설명하지 않았습니다.try,if,switch,while, 등, 다음과 같습니다.

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

// <===== BE DRAGONS } 

또한 코드가 실행되기 전에 처리되기 때문에 제어 구조에 있을 때 무엇을 해야 하는지 알기 어렵습니다.

ES2015까지는 명시되지 않았지만, 블록 단위의 함수 선언을 지원하는 것은 허용 가능한 확장이었습니다.안타깝게도(그리고 필연적으로) 엔진마다 다른 작업을 수행했습니다.

ES2015를 기준으로 사양서에 대처법이 기재되어 있습니다.실제로 다음과 같은 세 가지 작업을 수행할 수 있습니다.

  1. 웹 브라우저가 아닌 루즈모드일 경우 JavaScript 엔진은 한 가지 작업을 수행합니다.
  2. 웹브라우저에서 루즈모드일 경우 JavaScript 엔진은 다른 작업을 수행해야 합니다.
  3. strict 모드(브라우저 유무)의 경우 JavaScript 엔진은 다른 작업을 수행해야 합니다.

루즈 모드의 규칙은 까다롭지만 엄밀한 모드에서는 블록 내의 함수 선언이 간단합니다.블록에 로컬이며(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)); 

를 사용하지 않는 버전{ ... }표현 본문 또는 간결한 본문을 가진 화살표 함수(간결한 화살표 함수)라고 합니다.있는 사람{ ... }본문을 정의하는 것은 본문을 가진 화살표 함수입니다.(또한 자세한 화살표 함수)

개체 이니셜라이저의 메서드 선언(ES2015+)

ES2015에서는 메서드 정의라고 하는 함수를 참조하는 속성을 보다 짧은 형식으로 선언할 수 있습니다.이 형식은 다음과 같습니다.

var o = {
foo() {
} }; 

ES5 및 그 이전 버전에서는 다음과 거의 동등합니다.

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

(장황함을 제외한) 차이점은 방법이 사용할 수 있다는 것이다super단, 함수는 할 수 없습니다.예를 들어 다음과 같은 오브젝트가 있는 경우valueOf메서드 구문을 사용하면super.valueOf()가치를 얻다Object.prototype.valueOf(아마도 다른 작업을 하기 전에) ES5 버전은 다음과 같이 되어 있을 것입니다.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, 및 용으로 1개getFullName이것은 에 할당되어 있는 함수입니다.Person.prototype.




글로벌 콘텍스트에 대해서 말하자면var스테이트먼트와 aFunctionDeclaration마지막으로 글로벌 개체에 삭제할 수 없는 속성이 생성되지만 둘 다 값을 덮어쓸있습니다.

두 방법의 미묘한 차이는 변수 인스턴스화 프로세스가 실행될 때(실제 코드 실행 전) 모든 식별자가 다음과 같이 선언된다는 것입니다.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는 변수값과 마찬가지로 문제없이 덮어쓸 수 있습니다.예를 들어 다음과 같습니다.

 function test () {}
test = null; 

두 예제의 또 다른 분명한 차이점은 첫 번째 함수에 이름이 없지만 두 번째 함수에 이름이 있다는 것입니다.이러한 기능은 디버깅(콜 스택 검사 등) 시 매우 유용합니다.

편집한 첫 번째 예에 대해서(foo = function() { alert('hello!'); };선언되지 않은 과제입니다.항상 사용하실 것을 강력히 권장합니다.var키워드를 지정합니다.

임무가 있고, 그 임무가 없다면var스테이트먼트: 참조된 식별자가 스코프 체인에서 발견되지 않으면 글로벌오브젝트의 삭제 가능한 속성이 됩니다.

또한, 선언되지 않은 할당은ReferenceErrorECMAScript 5의 [Strict Mode]으로 설정합니다.

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

주의: 이 답변은 다른 질문에서 병합되었습니다. OP의 주요 의문점과 오해는 식별자가 다음과 같이 선언되었다는 입니다.FunctionDeclaration를 덮어쓸 수 없습니다.그렇지 않습니다.




당신이 게시한 두 개의 코드 조각은 거의 모든 목적에서 동일한 방식으로 작동합니다.

단, 동작의 차이는 첫 번째 변종(bariant:var functionOne = function() {}이 함수는, 코드의 그 시점 이후에만 호출할 수 있습니다.

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

이는 첫 번째 변형에서는 함수가 변수에 할당되기 때문입니다.foo실행 시.두 번째 단계에서는 함수가 해당 식별자에 할당됩니다.foo, 해석 시.

자세한 기술 정보

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

  1. 첫 번째 스니펫은 함수식을 나타내고 있습니다.여기에는 “함수” 연산자를 사용하여 함수를 만드는 작업이 포함됩니다. 연산자의 결과는 모든 변수 또는 객체 속성에 저장할 수 있습니다.함수 표현은 그렇게 강력합니다.함수식은 이름을 가질 필요가 없기 때문에 종종 “익명의 함수”라고 불립니다.
  2. 두 번째 예는 함수 선언입니다.이 명령어는 함수를 작성하기 위해 “function” 문을 사용합니다.이 함수는 해석 시 사용할 수 있으며 해당 범위 내의 모든 위치에서 호출할 수 있습니다.나중에 변수 또는 개체 속성에 저장할 수 있습니다.
  3. 함수를 정의하는 세 번째 방법은 원래 게시물에는 표시되지 않는 “Function()” 컨스트럭터입니다.이것은 와 동일하게 동작하기 때문에 사용하지 않는 것이 좋습니다.eval()그것에는 문제가 있습니다.