>  기사  >  웹 프론트엔드  >  JavaScript가 범위 감옥을 깨뜨립니다.

JavaScript가 범위 감옥을 깨뜨립니다.

黄舟
黄舟원래의
2017-02-27 14:25:11943검색

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는 실행 시 두 라운드에 걸쳐 코드를 스캔합니다. 첫 번째 라운드에서는 변수가 초기화되고 두 번째 라운드에서는 코드가 실행됩니다. 두 번째 실행 코드는 이해하기 쉽지만 첫 번째 라운드 프로세스는 더 모호합니다. 구체적으로 첫 번째 라운드에서는 다음 세 가지 작업을 수행합니다.

(1) 함수 매개변수 선언 및 초기화

(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();

이 프로그램은 오류를 보고하지 않으며 첫 번째 js 파일에서 액세스할 수 있습니다. App 네임스페이스의 후속 속성은 필요한 모든 할당 후에 프로그램 시작점이 수행되는 한 문제가 없어야 합니다. 이 예는 코드 구조의 합리적인 설계를 통해 js 언어의 동적 특성을 최대한 활용하는 방법을 성공적으로 보여줍니다.

이 글을 읽고 나면 독자들은 이 글이 약간의 헤드라인이라고 느낄 수도 있습니다. 위의 기술은 코드 레이아웃을 통해 만들어진 "환상"일 뿐입니다. 이전 코드가 존재하지 않는 속성에 액세스하는 것 같습니다. 실제로 실제 실행 순서는 합리적이고 정확합니다. 그런 다음 이 기사에서는 실제 "교차 작업 액세스" 기술을 소개합니다.

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 메서드를 사용합니다. 이는 완전한 범위 격리입니다.

js에는 eval(), setTimeout(), setInterval() 및 일부 기본 개체 구성 메서드와 같은 유사한 메서드가 많이 있습니다. 하지만 기억해야 할 두 가지 사항이 있습니다:

(1) 이 방법은 프로그램의 실행 효율성을 크게 떨어뜨립니다. js 자체가 해석된 언어이고 성능이 이미 컴파일된 언어보다 훨씬 느리다는 것은 누구나 알고 있습니다. 이를 토대로 eval과 같은 메서드를 사용하여 문자열 코드를 "재컴파일"하면 프로그램 성능이 훨씬 느려집니다.

(2) 이런 식으로 프로그래밍하면 코드의 복잡성이 크게 증가하고 작성한 코드를 몇 분 안에 이해할 수 없게 됩니다. 이 글에서는 독자들이 js의 문법적 특성을 포괄적으로 이해하여 더 나은 수정과 문제 해결을 할 수 있기를 바라면서 이 방법을 소개합니다. 이 문서에서는 프로덕션 수준 코드에서 두 번째 접근 방식을 사용하는 것을 전혀 권장하지 않습니다.

위 내용은 범위의 우리를 깨는 자바스크립트 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 주목해주세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.