내 JavaScript 함수 이름이 충돌하는 이유는 무엇입니까?


97

변수와 함수가 할당 된 함수가 이름이 충돌 할 때 어떤 일이 발생하는지보기 위해 다음 스크립트를 작성했습니다.

var f = function() {
    console.log("Me original.");
}

function f() {
    console.log("Me duplicate.");
}

f();

내가 얻는 출력은 "Me original"입니다. 다른 함수가 호출되지 않은 이유는 무엇입니까?

또한 원래 할당을로 변경 var f = new function() {하면 "Me original"이 표시되고 TypeError가 object is not a function. 누군가 설명해 주시겠습니까?


26
@ Dean.DePue — JavaScript 부분에는 혼동이 없습니다. 그것들을 다루는 규칙은 아주 분명합니다 (그리고 Benjamin이 그의 대답에서 설명했습니다).
Quentin

4
호기심은 언어를 배우는 가장 좋은 방법입니다. :-D
Cerbrus

2
또한, "자바 스크립트"와 같은 비 물질적 인 것이 혼란 스러움 (또는 그 문제에 대한 감정)을 "느끼는"것은 꽤 불가능하다고 생각합니다 ;-)
Cerbrus

2
두 번째 예에서 권상 순서를 반대로해야하는 이유는 무엇입니까?
Cerbrus

5
자바 스크립트에 대한 지식을 키우기위한 단계 : 1) '엄격한 사용'을 사용합니다. 2) 항상 jslint 또는 jshint를 사용합니다. 3) jslint 또는 jshint가 불평하는 항목을 찾습니다. 4) 헹구고 반복합니다.
steve-er-rino

답변:


170

함수 선언은 JavaScript에서 호이스트 (맨 위로 이동)됩니다. 구문 분석 순서는 올바르지 않지만 함수 선언이 호이스트되기 때문에 가지고있는 코드는 의미 상 다음과 동일합니다.

function f() {
    console.log("Me duplicate.");
}
var f = function() {
    console.log("Me original.");
}


f();

차례로 함수 이름을 제외하고는 다음과 같습니다.

var f = function() {
    console.log("Me duplicate.");
}
var f = function() {
    console.log("Me original.");
}


f();

차례로 가변 호이 스팅으로 인해 다음과 같습니다.

var f;
f = function() {
    console.log("Me duplicate.");
}
f = function() {
    console.log("Me original.");
}

f();

당신이 얻는 것을 설명하는 것은 함수를 재정의하고 있습니다. 보다 일반적으로 varJavaScript 에서는 여러 선언이 허용되며 이는 var x = 3; var x = 5완벽하게 합법적입니다. 새로운 ECMAScript 6 표준에서 let명령문은이를 금지합니다.

@kangax 의이 기사 는 자바 스크립트의 기능을 이해하는 데 환상적인 작업을 수행합니다.


2
당신은 정말 단순화 할 수 있습니다 function f()var f = function()그 정도? 호이 스팅과 기능 이름이 정말 유일한 차이점입니까?
djechlin 2014 년

6
이 질문의 맥락에서 @djechlin-예. 일반적으로 더 미묘 합니다. stackoverflow.com/questions/336859/… 참조 . 컴파일러 관점에서 보면 다르지만 프로그래머 관점에서 보면 우리는 그것을 주장하기에 충분히 가깝습니다 . 그래서 "파싱 순서는 틀렸지 만 당신이 가지고있는 코드는 의미 상 동일하다"는 대신 "같다"라고 덧붙였다. 좋은 지적.
Benjamin Gruenbaum 2014 년

1
@dotslash는 원래 질문을 편집하지 말고 변경하지 마십시오. 여기에서는 매너가 좋지 않은 것으로 간주됩니다. 또한 여러 질문을 하나로 혼합하는 것도 여기에서 매너가 나쁜 것으로 간주됩니다. 대신 새 질문을하거나 너무 사소하다고 생각되면 댓글에 설명을 요청하세요 (어쨌든 그게 바로 그 이유입니다). 위의 코드에서 버전은 모두f 호이스트되고 "Me Original"버전은 나중에 호이스트 됩니다 . 각각은 동일한 순서로 맨 위로 이동됩니다. 일반적으로 몇 가지 기능의 이름을 같은 방식으로 지정해서는 안됩니다. :)
Benjamin Gruenbaum

5
Strict 모드에서는 var동일한 범위에서 동일한 이름을 두 번 사용할 수 없습니다 .
Hoffmann

4
"그건 분명해야합니다"- 아마도 당신 에게는 분명하지만, 어느 시점에서 나에게는 분명하지 않았고, 그가 요청했을 때 OP에 분명하지 않았고, 이름을 지정했으며, 더 일반적으로 JavaScript에서 어휘 환경이 관리되는 방식은 하나였습니다. 자바 스크립트를 처음 배울 때 가장 이해하기 어려운 것들 중 하나입니다. 나는 그것을 이해하지 못하는 사람들을 그렇게 빨리 모욕하지 않을 것입니다.
Benjamin Gruenbaum 2014 년

10

후속 질문에 아무도 답변하지 않은 것 같으면 여기서 답변하겠습니다. 일반적으로 후속 질문은 별도의 질문으로해야합니다.

이유를 물었습니다.

var f = new function() {
    console.log("Me original.");
}

function f() {
    console.log("Me duplicate.");
}

f();

"나의 원본"을 인쇄합니다. 그리고 오류.

여기서 일어나는 일은 new함수가 생성자로 사용되는 원인입니다. 따라서 이것은 다음과 같습니다.

function myConstructor() {
    console.log("Me original.");
}
var f = new myConstructor();

function f() {
    console.log("Me duplicate.");
}

f();

Benjamin이 설명한 기능 호이 스팅 덕분에 위의 내용은 본질적으로 다음과 같습니다.

var myConstructor = function() {
    console.log("Me original.");
};
var f = function() {
    console.log("Me duplicate.");
};

f = new myConstructor();

f();

이 표현 :

var f = new function() {
    console.log("Me original.");
}

f익명 함수를 생성자로 사용하여 새 객체를 생성하고에 할당합니다 . "나 오리지널." 생성자가 실행되면 출력됩니다. 그러나 생성 된 객체는 그 자체가 함수가 아니므로 이것이 결국 실행될 때 :

f();

f함수가 아니기 때문에 오류가 발생 합니다.


오, 훌륭합니다! 답변 해 주셔서 감사합니다! :) :)
ankush981 2014-06-04

2

이것이 포인트 추가에 접근하는 잘못된 방법이라면 저를 용서하십시오. 나는 여기에 많이 가본 적이 없으며 건설적인 지시 및 / 또는 비판을 환영 할 것입니다.

Benjamin의 답변은 OP의 질문을 훌륭하게 다루지 만, 호이 스팅과 그 이상한 점에 대한 전체 둘러보기를 제공하는 하나의 조정을 추가하고 싶습니다.

다음과 같이를 호출하여 원래 코드를 시작하면 f:

f();

var f = function() {
   console.log("Me original.");
};

function f() {
   console.log("Me duplicate.");
}

f();

출력은 다음과 같습니다.

Me duplicate.
Me original.

그 이유는 그 varfunction진술이 약간 다른 방식으로 게양되기 때문입니다.

들어 선언 현재 범위의 *의 상단으로 이동하지만, 어떤 과제가 게양되지 않습니다. 선언 된 var의 값이가는 한 원래 할당 줄에 도달 할 때까지 정의되지 않습니다.var

들어 function , 선언 모두 정의가 게양된다. 구조에 사용 된 함수 표현식var f = function() {... 은 호이스트되지 않습니다.

따라서 호이 스팅 후 실행은 코드가 다음과 같습니다.

var f; // declares var f, but does not assign it.

// name and define function f, shadowing the variable
function f() { 
  console.log("Me duplicate.");
}

// call the currently defined function f
f(); 

// assigns the result of a function expression to the var f,
// which shadows the hoisted function definition once past this point lexically
f = function() { 
  console.log("Me original."); 
}

// calls the function referenced by the var f
f();

* 모든 JavaScript 범위는 어휘 또는 기능, 범위이지만 그 시점에서 f 단어를 사용하면 혼란 스러울 것 같았습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.