이번에는 js의 (function(){xxx})() 사용에 대한 자세한 설명을 가져왔는데, js의 (function(){xxx})() 사용 시 주의사항은 무엇이며, 다음은 실무적인 내용입니다. 사례를 살펴보겠습니다. 살펴보겠습니다.
self-executinganonymous function:
에서 분석 작성: (function() { /* code */ } ) ();
설명: 함수 (function(){})를 둘러싸는 첫 번째 대괄호 쌍은 이름이 지정되지 않은 함수를 스크립트에 반환한 다음, 빈 대괄호 쌍은 반환된 이름이 없는 함수를 즉시 실행합니다. 대괄호는 익명의 함수 매개변수입니다.
함수: 이 특수 함수 패키지에 모든 코드를 작성하는 한 이를 사용하여 네임스페이스를 만들 수 있습니다. 허용하지 않는 한 외부에서 액세스할 수 없습니다. 변수이므로 함수 또는 변수가 전역이 됩니다.) 각 JavaScript 라이브러리의 코드는 기본적으로 이런 방식으로 구성됩니다.
요약하자면, 실행 함수의 주요 기능은 익명 및 자동 실행입니다. 코드는 해석될 때 이미 실행 중입니다.
다른 쓰기 방법
<span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 14px;'>(function () { /* code */ } ()); <br>!function () { /* code */ } ();<br>~function () { /* code */ } ();<br>-function () { /* code */ } ();<br>+function () { /* code */ } ();</span>
요즘 시간이 좀 있어서 마음을 차분히 정리하고 다양한 코드를 볼 수 있는 함수와 느낌표가 자주 등장하는 게 생각나네요. 2달 전에 내가 한 일. 마침내 항저우에서 열린 팀 회의에 참석했을 때 @西子剑影님이 같은 질문을 하셨습니다. 기능 앞에 느낌표(!)를 추가하면 어떻게 될까요? 예를 들어 다음 코드는
<span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 14px;'>!function(){alert('iifksp')}() // true</span>
콘솔에서 실행한 후 얻은 값이 true입니다. 이 익명 함수는 값을 반환하지 않고 기본 반환 값이 정의되지 않기 때문에 이것이 true인 이유를 이해하기 쉽습니다. 부정 결과는 매우 자연스럽습니다. 따라서 문제는 결과 값에 관한 것이 아니라 왜 부정 연산을 통해 익명 함수의 자체 조정을 합법적으로 만들 수 있습니까?
익명 함수를 호출하기 위해 괄호를 추가하는 것이 더 익숙할 수도 있습니다.
<span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 14px;'>(function(){alert('iifksp')})() // true</span>
또는
<span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 14px;'>(function(){alert('iifksp')}()) // true</span>
위 괄호의 위치는 다르지만 효과는 완전히 동일합니다.
그럼 많은 분들이 이 느낌표 방식을 애용하게 만드는 장점은 무엇일까요? 문자 하나만 저장하는 것이라면 너무 불필요합니다. 100K 라이브러리라도 많은 공간을 절약할 수는 없습니다. 공간이 아니기 때문에 시간적 고려가 있을 수 있다는 의미이며, 성능에 대해서는 기사 마지막 부분에 언급되어 있습니다.
핵심 질문으로 돌아가서, 왜 이것이 가능할까요? 더욱 중요한 질문은 이것이 왜 필요한가입니다.
사실 괄호든 느낌표든 전체 문장이 합법적으로 할 수 있는 일은 딱 하나, 함수 선언문을 표현식으로 바꾸는 것뿐입니다.
<span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 14px;'>function a(){alert('iifksp')} // undefined</span>
这是一个函数声明,如果在这么一个声明后直接加上括号调用,解析器自然不会理解而报错:
<span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 14px;'>function a(){alert('iifksp')}() // SyntaxError: unexpected_token</span>
因为这样的代码混淆了函数声明和函数调用,以这种方式声明的函数 a,就应该以 a(); 的方式调用。
但是括号则不同,它将一个函数声明转化成了一个表达式,解析器不再以函数声明的方式处理函数a,而是作为一个函数表达式处理,也因此只有在程序执行到函数a时它才能被访问。
所以,任何消除函数声明和函数表达式间歧义的方法,都可以被解析器正确识别。比如:
<span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 14px;'>var i = function(){return 10}(); // undefined 1 && function(){return true}(); // true 1, function(){alert('iifksp')}(); // undefined</span>
赋值,逻辑,甚至是逗号,各种操作符都可以告诉解析器,这个不是函数声明,它是个函数表达式。并且,对函数一元运算可以算的上是消除歧义最快的方式,感叹号只是其中之一,如果不在乎返回值,这些一元运算都是有效的:
<span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 14px;'>!function(){alert('iifksp')}() // true+function(){alert('iifksp')}() // NaN-function(){alert('iifksp')}() // NaN~function(){alert('iifksp')}() // -1</span>
甚至下面这些关键字,都能很好的工作:
<span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 14px;'>void function(){alert('iifksp')}() // undefined new function(){alert('iifksp')}() // Object delete function(){alert('iifksp')}() // true</span>
最后,括号做的事情也是一样的,消除歧义才是它真正的工作,而不是把函数作为一个整体,所以无论括号括在声明上还是把整个函数都括在里面,都是合法的:
<span style='font-family: 微软雅黑, "Microsoft YaHei"; font-size: 14px;'>(function(){alert('iifksp')})() // undefined(function(){alert('iifksp')}()) // undefined</span>
说了这么多,实则在说的一些都是最为基础的概念——语句,表达式,表达式语句,这些概念如同指针与指针变量一样容易产生混淆。虽然这种混淆对编程无表征影响,但却是一块绊脚石随时可能因为它而头破血流。
最后讨论下性能。我在jsperf上简单建立了一个测试:http://jsperf.com/js-funcion-expression-speed ,可以用不同浏览器访问,运行测试查看结果。我也同时将结果罗列如下表所示(由于我比较穷,测试配置有点丢人不过那也没办法:奔腾双核1.4G,2G内存,win7企业版):
Option | Code | Ops/sec | |||
---|---|---|---|---|---|
Chrome 13 | Firefox 6 | IE9 | 사파리 5 | ||
! | !function(){;}() | 3,773,196 | 10,975,198 | 572,694 | 2,810, 197 |
+ | +function(){; }() | 21,553,847 | 12,135,960 | 572,694 | 1,812,238 |
- | -함수(){;}() | 21,553,847 | 12,135,960 | 572,694 | 1,864,155 |
~ | ~function(){;}() | 3,551,136 | 3,651,652 | 572,694 | 1,876,002 |
(1) | (함수(){;})() | 3,914,953 | 12,135,960 | 572,694 | 3,025,608 |
(2) | (함수(){;}()) | 4,075,201 | 12,135,960 | 572,694 | 3,025,608 |
void | void function(){;}() | 4,030,756 | 12,135,960 | 572,694 | 3,025,608 |
new | 새 함수(){;}() | 619,606 | 299,100 | 407,104 | 816,903 |
delete | delete 함수(){;}() | 4,816,225 | 12,135,960 | 572,694 | 2,693,524 |
= | var i = 함수(){;}() | 4,984,774 | 12,135,960 | 565,982 | 2,602,630 |
&& | 1 && 함수(){;}( ) | 5,307,200 | 4,393,486 | 572,694 | 2,565,645 |
|| | 0 || 기능(){;}() | 5,000,000 | 4,406,035 | 572,694 | 2,490,128 |
& | 1 & function(){;}() | 4,918,209 | 12,135,960 | 572,694 | 1,705,551 |
| | 1 | 함수(){;}() | 4,859,802 | 12,135,960 | 572,694 | 1,612,372 |
^ | 1 ^ 함수(){;}() | 4,654,916 | 12,135,960 | 572,694 | 1,579,778 |
, | 1, 함수(){;}() | 4,878,193 | 12,135,960 | 572,694 | 2,281,186 |
다른 방법으로 생성 된 결과는 동일하지 않으며 차이가 크고 브라우저마다 다르다는 것을 알 수 있습니다.
하지만 여전히 많은 공통점을 찾을 수 있습니다. 새로운 방법은 항상 가장 느립니다. 물론 그렇습니다. 그 외 여러 측면에서 차이는 사실 크지 않지만, 한 가지 확실한 것은 느낌표가 가장 이상적인 선택은 아니라는 것입니다. 반면 전통적인 괄호는 항상 테스트에서 매우 빠르게 수행되며 대부분의 경우 느낌표보다 빠르므로 일반적으로 사용하는 방법에는 문제가 없으며 최적이라고 할 수도 있습니다. 더하기 및 빼기 기호는 Chrome에서 놀라운 성능을 발휘하고 일반적으로 다른 브라우저에서도 빠르며 느낌표보다 더 잘 작동합니다.
물론 이는 단순한 테스트일 뿐이며 문제를 설명할 수는 없습니다. 그러나 일부 결론은 의미가 있습니다. 괄호와 더하기 및 빼기 기호가 최적입니다.
그런데 왜 그렇게 많은 개발자가 느낌표를 좋아할까요? 이는 단지 습관의 문제일 뿐, 그 사이의 장단점은 완전히 무시할 수 있다고 생각합니다. 코딩 스타일에 익숙해지면 이 규칙은 프로그램을 혼란스러운 것에서 읽기 쉬운 것으로 바꿔줄 것입니다. 느낌표에 익숙해지면 괄호보다 가독성이 더 좋다는 점을 인정해야 합니다. 읽을 때 괄호 매칭에 신경쓰지 않아도 되고, 쓸 때 함부로 잊어버릴 필요도 없고——
그렇게 하다가 너무 자랑스러워서 한 글자 더 저장했을 때, 급하게 읽다가 잊어버렸다. 굴러간 C언어 교과서의 당혹감과 황당함... 누구나 가끔 잊어버리고, 다시 집어 들었을 때, 잊어버린 것만이 아니다.
이 기사의 사례를 읽으신 후 방법을 마스터하셨다고 생각합니다. 더 흥미로운 정보를 보려면 PHP 중국어 웹사이트의 다른 관련 기사를 주목하세요!
추천 도서:
JS 프레임워크 라이브러리 사용 사례에 대한 자세한 설명
네이티브 js를 사용하여 별이 빛나는 하늘 효과를 만드는 방법
위 내용은 js에서 (function(){xxx})() 사용에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!