1. JavaScript 선언 승격
js에는 변수 선언 승격, 함수 선언 승격이라는 특성이 있다는 것을 많은 사람들이 알고 있어야 합니다. 이전에 이해했는지 여부에 관계없이 다음 코드를 실행한 결과가 기대에 부합하는지 확인하세요.
var a=123; //可以运行 abc(); //报错:def is not a function def(); function abc(){ //undefined console.log(a); var a="hello"; //hello console.log(a); } var def=function(){ console.log("def"); }
사실 js는 실행 시 두 라운드에 걸쳐 코드를 스캔합니다. 첫 번째 라운드에서는 변수가 초기화되고 두 번째 라운드에서는 코드가 실행됩니다. 두 번째 실행 코드는 이해하기 쉽지만 첫 번째 라운드 프로세스는 더 모호합니다. 구체적으로 첫 번째 라운드에서는 다음 세 가지 작업을 수행합니다.
(2) 익명 함수를 로컬 변수에 할당하는 것을 포함하여 로컬 변수를 선언합니다. 초기화하지 마세요
(3) 함수 선언 및 초기화
이러한 이론적 기초를 이해한 후 위 코드는 실제로 1차 스캔 후 js 컴파일러에 의해 "번역"되었습니다.”는 다음과 같습니다. code:
var a; a=123; function abc(){ //局部变量,将会取代外部的a var a; //undefined console.log(a); var a="hello"; //hello console.log(a); } var def; //可以运行 abc(); //报错:def is not a function def(); var def=function(){ console.log("def"); }
이제 주석에 표시된 프로그램 런타임 출력을 살펴보겠습니다. 이것이 js 선언 프로모션이 수행하는 역할입니다.
js 선언 승격 메커니즘을 알고 나면 다음 코드를 살펴보겠습니다.
var obj={}; function start(){ //undefined //This is obj.a console.log(obj.a); //undefined //This is a console.log(a); //成功输出 //成功输出 console.log("页面执行完成"); } start(); var a="This is a"; obj.a="This is obj.a"; start();위 주석의 첫 번째 줄은 start() 메서드가 처음 실행되는 시점을 나타냅니다. . 출력, 두 번째 줄은 start() 메서드의 두 번째 실행 결과를 나타냅니다. js 선언 승격이 존재하기 때문에 start() 메소드를 두 번 실행했을 때 오류가 보고되지 않은 것을 확인할 수 있습니다. 이 예제를 약간 수정해 보겠습니다.
var obj={}; function start(){ //undefined //This is obj.a console.log(obj.a); //报错 //This is a console.log(a); //因为上一行的报错导致后续代码不执行 //成功输出 console.log("页面执行完成"); } start(); /*---------------另一个js文件----------------*/ var a="This is a"; obj.a="This is obj.a"; start();이때 a 변수 선언을 다른 js 파일로 미루었기 때문에 console.log(a) 코드가 처음으로 실행됩니다. 오류가 보고되어 후속 js 코드가 더 이상 실행되지 않습니다. 그러나 start() 메서드는 두 번째에도 여전히 정상적으로 실행됩니다. 이것이 바로 거의 모든 곳에서 "js 네임스페이스"를 사용하여 다양한 js 파일을 배포하는 것이 권장되는 이유입니다. 아래에서는 코드 조각을 사용하여 선언 승격 + 네임스페이스가 어떻게 "행동의 우리"를 교묘하게 깨뜨릴 수 있는지 요약합니다.
/*-----------------第一个js文件----------------*/ var App={}; App.first=(function(){ function a(){ App.second.b(); } return { a:a }; })(); /*-----------------另一个js文件----------------*/ App.second=(function(){ function b(){ console.log("This is second.b"); } return { b:b }; })(); //程序起点,输出This is second.b App.first.a();
이 글을 읽고 나면 독자들은 이 글이 약간의 헤드라인이라고 느낄 수도 있습니다. 위의 기술은 코드 레이아웃을 통해 만들어진 "환상"일 뿐입니다. 이전 코드가 존재하지 않는 속성에 액세스하는 것 같습니다. 실제로 실제 실행 순서는 합리적이고 정확합니다. 그런 다음 이 기사에서는 실제 "교차 작업 액세스" 기술을 소개합니다.
2.js 실행 코드
js 언어에는 "정말로 새장을 부수는" 대표적인 방법인 "eval()" 메서드가 있다는 것은 누구나 알고 있습니다. 아래 코드를 보세요:
(function(){ var code="console.log(a)"; //This is a bird test(code); function test(code){ console.log=function(arg){ console.info("This is a "+arg); }; var a="bird"; eval(code); } })();
이 코드를 읽고 나면 많은 사람들이 js의 경이로움에 "이것도 작동할 수 있을까?!"라는 의문에 한숨을 쉬게 될 것입니다. 예. test() 메소드는 선언 승격 메커니즘으로 인해 미리 호출되어 정상적으로 실행될 수 있습니다. test() 메소드는 코드 매개변수를 허용합니다. test() 메소드 내에서 console.log 메소드를 다시 작성하고 출력 형식을 수정했으며 테스트 내에 개인 변수 var a="bird"를 정의했습니다. 테스트 메서드가 끝나면 eval을 사용하여 코드를 동적으로 실행합니다. 인쇄 결과는 매우 마술적입니다. 브라우저는 테스트 메서드 내에서 개인 변수 a를 인쇄하기 위해 다시 작성한 console.log 메서드를 사용합니다. 이는 완전한 범위 격리입니다.
(1) 이 방법은 프로그램의 실행 효율성을 크게 떨어뜨립니다. js 자체가 해석된 언어이고 성능이 이미 컴파일된 언어보다 훨씬 느리다는 것은 누구나 알고 있습니다. 이를 토대로 eval과 같은 메서드를 사용하여 문자열 코드를 "재컴파일"하면 프로그램 성능이 훨씬 느려집니다.
(2) 이런 식으로 프로그래밍하면 코드의 복잡성이 크게 증가하고 작성한 코드를 몇 분 안에 이해할 수 없게 됩니다. 이 글에서는 독자들이 js의 문법적 특성을 포괄적으로 이해하여 더 나은 수정과 문제 해결을 할 수 있기를 바라면서 이 방법을 소개합니다. 이 문서에서는 프로덕션 수준 코드에서 두 번째 접근 방식을 사용하는 것을 전혀 권장하지 않습니다.
위 내용은 범위의 우리를 깨는 자바스크립트 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 주목해주세요!