JavaScript 함수의 이름을 지정하고 즉시 실행할 수 있습니까?


90

나는 이것들 중 꽤있다 :

function addEventsAndStuff() {
  // bla bla
}
addEventsAndStuff();

function sendStuffToServer() {
  // send stuff
  // get HTML in response
  // replace DOM
  // add events:
  addEventsAndStuff();
}

DOM이 변경 되었기 때문에 이벤트를 다시 추가해야하므로 이전에 첨부 된 이벤트가 사라집니다. 초기에도 부착해야하므로 (duh) DRY 기능이 좋다.

이 설정에는 아무런 문제가 없습니다 (또는 거기에 있습니까?). 조금 부드럽게 할 수 있습니까? addEventsAndStuff()함수 를 생성 하고 즉시 호출하고 싶어서 그렇게 아마추어 적으로 보이지 않습니다.

다음 두 가지 모두 구문 오류로 응답합니다.

function addEventsAndStuff() {
  alert('oele');
}();

(function addEventsAndStuff() {
  alert('oele');
})();

수취인이 있습니까?



2
아니요, @CristianSanchez.
Máxima Alekz

Imho 두 번째 코드 블록은 읽기 어렵습니다. 첫 번째 코드 블록에서는 모든 판독기에서 init 후에 함수를 호출하는 것이 분명합니다. 독자는 끝에서 닫는 대괄호를 무시하는 경향이 있습니다.
kaiser

답변:


123

질문에 게시 한 예제에는 문제가 없습니다. 다른 방법은 이상하게 보일 수 있지만 다음과 같습니다.

var addEventsAndStuff;
(addEventsAndStuff = function(){
    // add events, and ... stuff
})();

JavaScript에서 함수를 정의하는 방법에는 두 가지가 있습니다. 함수 선언 :

function foo(){ ... }

이고 함수식, 임의의 상기 이외의 함수를 정의하는 방법 :

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

...기타

함수 표현식은 이름을 지정할 수 있지만 그 이름은 포함하는 범위로 전파되지 않습니다. 이 코드가 유효 함을 의미합니다.

(function foo(){
   foo(); // recursion for some reason
}());

그러나 이것은 아닙니다 :

(function foo(){
    ...
}());
foo(); // foo does not exist

따라서 함수의 이름을 지정하고 즉시 호출하려면 지역 변수를 정의하고 함수를 표현식으로 할당 한 다음 호출해야합니다.


1
"함수 식에 이름을 지정할 수 있음" 이름이 지정된 함수 식에주의하십시오. 그들은 해야 당신이 설명하는대로 작동하지만 그들은 IE9 이전 IE에하지 않는다 - 당신이 얻는 함수, 함수 이름 누수를. 세부 정보 : kangax.github.com/nfe (이것은 IE9에서 마침내 수정되었습니다.)
TJ Crowder

@TJ-참조 주셔서 감사합니다. 최종 제품을 테스트하는 것 외에는 IE를 사용하지 않았기 때문에 나는 IE9가 IE7 / 8 모드로 설정할 때이 버그를 에뮬레이션하지 않는다고 가정하고 있습니다. 여전히 IE9 JS 엔진을 사용하는 것 같습니다. Meh
Mark Kahn

저처럼이 방법으로 jshint 문제가 발생하면 call()여기 에서 방법을 사용할 수 있습니다 . stackoverflow.com/a/12359154/1231001
cfx

이 접근 방식은 특정 상황에서 유용 해 보일 수 있지만 읽기가 조금 더 어렵지만 거의 동일한 양의 텍스트를 가지고있는 것 같습니다.
Vladimir

16

이것에 대한 좋은 속기가 있습니다 (함수 할당에 변수를 선언 할 필요가 없습니다) :

var func = (function f(a) { console.log(a); return f; })('Blammo')

r함수는 어떤 것을 반환합니까? function rvar r? 그냥 궁금해. 좋은 솔루션입니다. 그래도 하나의 loc 일 필요는 없었습니다 =)
Rudie

나는 좀 더 명확하게하기 위해 이름을 변경했습니다,하지만이 return r을했을 function r그의 그것의 범위를했다한다. 한 줄에 무언가를 얻기 위해 영구적으로 Scala를 작성했습니다.
James Gorrie 2014 년

@JamesGorrie, Brilliant 속기, 그러나 콘솔에서 두 번 시도했지만 func, func (), func () () 모두 f ()의 함수 선언을 반환하지만 예상대로 func ()에 의해 'Blammo'를 출력 할 수 있습니까? :)?
mike652638

@ mike652638 내 콘솔에서 실행했는데 콘솔 로그 blammo?
James Gorrie

5

이 설정에는 아무런 문제가 없습니다 (또는 거기에 있습니까?). 조금 부드럽게 할 수 있습니까?

대신 이벤트 위임을 사용하십시오. 여기서 사라 지지 않는 컨테이너에서 이벤트를 실제로 관찰 한 다음 event.target(또는 event.srcElementIE에서) 이벤트가 실제로 발생한 위치를 파악하고 올바르게 처리합니다.

이렇게하면 핸들러를 한 번만 연결하면 콘텐츠를 교체해도 계속 작동합니다.

다음은 도우미 라이브러리를 사용하지 않는 이벤트 위임의 예입니다.

(function() {
  var handlers = {};

  if (document.body.addEventListener) {
    document.body.addEventListener('click', handleBodyClick, false);
  }
  else if (document.body.attachEvent) {
    document.body.attachEvent('onclick', handleBodyClick);
  }
  else {
    document.body.onclick = handleBodyClick;
  }

  handlers.button1 = function() {
    display("Button One clicked");
    return false;
  };
  handlers.button2 = function() {
    display("Button Two clicked");
    return false;
  };
  handlers.outerDiv = function() {
    display("Outer div clicked");
    return false;
  };
  handlers.innerDiv1 = function() {
    display("Inner div 1 clicked, not cancelling event");
  };
  handlers.innerDiv2 = function() {
    display("Inner div 2 clicked, cancelling event");
    return false;
  };

  function handleBodyClick(event) {
    var target, handler;

    event = event || window.event;
    target = event.target || event.srcElement;

    while (target && target !== this) {
      if (target.id) {
        handler = handlers[target.id];
        if (handler) {
          if (handler.call(this, event) === false) {
            if (event.preventDefault) {
              event.preventDefault();
            }
            return false;
          }
        }
      }
      else if (target.tagName === "P") {
        display("You clicked the message '" + target.innerHTML + "'");
      }
      target = target.parentNode;
    }
  }

  function display(msg) {
    var p = document.createElement('p');
    p.innerHTML = msg;
    document.body.appendChild(p);
  }

})();

라이브 예

페이지에 동적으로 추가되는 메시지를 클릭하면 추가되는 새 단락에 이벤트를 연결하는 코드가 없더라도 클릭이 등록되고 처리됩니다. 또한 핸들러가 맵의 항목 일 뿐이며 모든 디스패치를 ​​수행 하는 핸들러 가 하나document.body 있습니다. 이제, 당신은 아마도 이것을보다 더 표적화 된 것에 뿌리 document.body를 내릴 것입니다. 그러나 당신은 아이디어를 얻습니다. 또한 위의 경우 기본적으로로 발송하고 id있지만 원하는대로 복잡하거나 간단하게 매칭 할 수 있습니다.

jQuery , Prototype , YUI , Closure 또는 기타 여러 가지 와 같은 최신 JavaScript 라이브러리는 브라우저 차이를 완화하고 가장자리 사례를 깔끔하게 처리 할 수있는 이벤트 위임 기능을 제공해야합니다. jQuery는 livedelegate함수 를 모두 사용하므로 전체 범위의 CSS3 선택기 (및 일부)를 사용하여 핸들러를 지정할 수 있습니다.

예를 들어, 다음은 jQuery를 사용하는 동등한 코드입니다 (jQuery가 위의 최신 원시 버전이 처리하지 않는 경우를 제외하고는 예외입니다).

(function($) {

  $("#button1").live('click', function() {
    display("Button One clicked");
    return false;
  });
  $("#button2").live('click', function() {
    display("Button Two clicked");
    return false;
  });
  $("#outerDiv").live('click', function() {
    display("Outer div clicked");
    return false;
  });
  $("#innerDiv1").live('click', function() {
    display("Inner div 1 clicked, not cancelling event");
  });
  $("#innerDiv2").live('click', function() {
    display("Inner div 2 clicked, cancelling event");
    return false;
  });
  $("p").live('click', function() {
    display("You clicked the message '" + this.innerHTML + "'");
  });

  function display(msg) {
    $("<p>").html(msg).appendTo(document.body);
  }

})(jQuery);

라이브 카피


나는 Event.target올바른 대상이 아니기 때문에을 사용하고 싶지 않습니다. 맞습니다. 당신은 클릭하면 IMG내부 DIV와이 DIV이벤트를 갖고, Event.target될 것 IMG하고 얻을 수있는 방법은 없습니다 DIV잘 객체. 편집 Btw은 내가 jQuery의 증오 .live'이벤트'
Rudie

@Rudie : Re event.target: 당신이 설명하는 것은 틀린 것이 아닙니다. 맞습니다. 당신은 클릭하면 img내부 a를 div하고를보고있는 div, event.target은 IS img(그리고 this는 IS div). 위의 내용을 다시 살펴보십시오. 클릭 한 요소 ( img예 :)와보고있는 요소 (위에서에서 끝까지) 사이의 체인의 어느 지점에서든 핸들러를 연결할 수 있습니다 document.body. Re live: delegate더 포함 된 버전을 선호합니다 live. 나는 live원시 예제에서 한 것과 가장 가깝기 때문에 위에서 사용 했습니다. Best,
TJ Crowder

4

다음과 같은 도우미 함수를 만들 수 있습니다.

function defineAndRun(name, func) {
    window[name] = func;
    func();
}

defineAndRun('addEventsAndStuff', function() {
    alert('oele');
});

2
이것이 왜 나쁜 해결책입니까? 함수가 전역 네임 스페이스에 등록 되었기 때문에? 누가 이것을 찬성 했습니까?
Rudie 2011-06-19

좋은 생각 :)) -
최대 Alekz

4

코드에 오타가 있습니다.

(function addEventsAndStuff() {
  alert('oele');
)/*typo here, should be }*/)();

그래서

(function addEventsAndStuff() {
  alert('oele');
 })();

공장. 건배!

주석을 기반으로 [ 편집 ] : 그리고 이것은 한 번에 함수를 실행하고 반환해야합니다.

var addEventsAndStuff = (
 function(){
  var addeventsandstuff =  function(){
    alert('oele');
  };
  addeventsandstuff();
  return addeventsandstuff;
 }()
);

멍청한 괄호는 모두 닮았다 !! 감사! 참으로 건배!
Rudie 2011-06-19

네 .. 그래서 .. 사실 그건 안되네요. 이 함수는 즉시 실행됩니다.하지만 어디에도 등록되지 않았으므로 다시 호출합니다.->ReferenceError
Rudie

@Rudie : 방금 KomodoEdit가 내가 항상 Aptana Studio가하기를 원했지만 (항상 중단 된) 모든 작업을 수행하고 있으며, 그 외에도 구성이 가능하고 빠르며 유용한 애드온으로 가득 차 있다는 것을 알게되었습니다. 일치하는 괄호를 강조 표시합니다. 일치하는 괄호에 확고한 빨간색 경고 색상을 지정할 수도 있습니다! :이 무료 한번 시도해 activestate.com/komodo-edit
KooiInc

야 ... (그리고 분명히 내가하지 바탕 화면 편집기에서 SO 웹 편집기에서 입력.)
Rudie

그리고 그것은 많은 추가 타이핑과 무엇을 어떻게 타이핑하는지 기억하는 것입니다. 나는 원래 (작동하지 않는) 솔루션을 좋아하지만, 새)가 너무 어렵다 =입니다
Rudie

2

ES6를 사용하면 더 간단합니다.

var result = ((a, b) => `${a} ${b}`)('Hello','World')
// result = "Hello World"
var result2 = (a => a*2)(5)
// result2 = 10
var result3 = (concat_two = (a, b) => `${a} ${b}`)('Hello','World')
// result3 = "Hello World"
concat_two("My name", "is Foo")
// "My name is Foo"

그래서 어떻게 다시 부를까요? 이름이 뭐죠? 기능이 아닌 결과 만 유지합니다.
Rudie

이 메서드는 즉시 호출해야하고 다시 실행하지 않으려는 경우에만 사용됩니다. 어쨌든 나는 그것을 다시 부를 수있는 방법을 보여주기 위해 대답을 편집 할 것입니다. 어떻게 생각하십니까? @Rudie
Alberto

1
내 질문은 이름을 지정하고 다시 실행하는 것이 었습니다. concat_two완벽하게 작동하지만 항상 전역 범위에서 정의하므로 "use strict". 그것은 나에게 중요하지 않지만 작은 단점입니다.
Rudie

1

함수를 생성하고 즉시 실행하려면-

// this will create as well as execute the function a()
(a=function a() {alert("test");})();

// this will execute the function a() i.e. alert("test")
a();

1
당신이 (위처럼), 당신이 사용하고 오른손 값으로 명명 된 기능을 사용할 때주의 라는 이름의 함수 표현식 은 동안 해야 전쟁에서 충격 - - 유효 불행하게도 대부분 다양한 구현 (에 문제가 있습니다를 IE를 ). 세부 정보 : kangax.github.com/nfe
TJ Crowder

0

그렇게 해보십시오.

var addEventsAndStuff = (function(){
    var func = function(){
        alert('ole!');
    };
    func();
    return func;
})();

1
이것은 가깝지만 var foo = (function() {...})();할당 전에 함수를 호출합니다. 괄호에는 할당이 포함되어야합니다. (할당 하고 전화 걸고 싶습니다 .)
David

그것은 또한 많은 타이핑과 타이핑을 기억하는 것입니다. 그런 다음 차라리 현재 통화를 사용합니다.
Rudie 2011-06-19
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.