3.javascript-함수 생성 철저히 이해

13894 단어
var a = 2;

function foo() {
    console.log(a)
}

function bar(){
    var a = 5;
    foo()
}

bar()//2

위 코드에 대한 설명은 정적 작용역, 함수의 작용역은 창설할 때의 환경과 관련이 있다.그러나 우리는 다른 코드를 보았다.
var a = 1;

function foo() {

    var a = 2;
    function innerOne(){
        console.log(a)
    }
    
    var innerTwo = new Function("console.log(a)")
    
    var innerTree =  function (){
        console.log(a)
    }

    innerOne();
    innerTwo();
    innerTree();
}

foo();//2 1 2 

var innerTwo = new Function("console.log(a)")에 대해 innerTwo라는 함수도foo에서 만들어지지 않았습니까?왜 얘가 1을 인쇄해?
분명히 다른 방식으로 만들어진 함수는 약간의 차이가 있다.
이 편과 다음 편(함수 운행)에서 우리는 정적 작용역,'함수는 그것을 만들 때의 어법 환경과만 관련이 있다'는 것이 무슨 뜻인지 더 설명할 것이다.함수의 역할 영역을 이해하려면 두 가지 문제를 연구해야 한다.
  • 함수는 언제 생성됩니까?
  • 함수 생성 과정은 모두 무엇을 했습니까?

  • 이 두 문제에 대하여 우리 하나씩 이야기하자.
    함수는 언제 생성됩니까?다른 방식으로 정의된 함수는 다음과 같습니다.

    함수 설명


    이와 같은 함수를 정의하는 문장을 함수 성명이라고 한다.
    function functionname ( parameters ) {
        functionbody
    }
    

    함수 성명에 대해 말하자면, 함수 성명은 var 성명과 마찬가지로 코드가 실행되기 전에 만들어진 것이다.뭐?얘들아, 또 어지러워. 코드도 아직 실행하지 않았는데 어떻게 만들어?
    따라서 JS의 3가지 실행 가능한 코드(global\function\eval)의 실행 모델을 설명해야 한다.
             =          + var         scan +     ;
    

    그래서 약속을 한다. 내가 코드가 실행된다고 말할 때 이 프로그램에 들어가거나 이 함수에 들어가는 것을 의미한다.코드가 실행된다고 말할 때, 일부 전주가 준비되어 있음을 표시합니다. (상하문 초기화 + var 성명과 함수 성명 스캔scan을 실행합니다.) 구분을 표시하기 위해 한 줄의 실행 문장을 시작합니다.
    따라서 함수 성명은 var 성명과 마찬가지로 스캔 코드를 분석하는 단계에서 상행문을 실행하는 어법 환경에 등록되기 때문에'향상'현상도 있다.var과 달리 등록 단계에서 var 성명은undefined로 초기화되고 함수는 메모리에 함수 대상을 만들고 이 함수 대상으로 초기화됩니다.그래서 함수'승급'은 undefined가 아닌 직접 사용할 수 있습니다.
    
    lex() //'lexical'
    function lex() {
        console.log('lexical')
    }
    

    여기서 우리는 함수 성명에 대해 함수는'var 성명과 함수 성명이scan'을 스캔할 때 만들어진다는 결론을 얻었다.

    함수 생성


    함수 작성 프로세스는 다음과 같습니다.
    /**
     *          
     */
     
    function  FunctionCreate(parameterList,functionBody,scope,strict) {
        var F = Object.create();
        F. [[Class]] = "Function";
        F.[[Code]] = functionBody;
        F. [[FormalParameters]] = parameterList;
        F. [[Prototype]] = Function.prototype;
        F.[[Scope]] = scope;
        F.prototype = {
            constructor:F
        };
        F. [[Call]] = [[internal method]];
        //  Strict  Strict     
        //        
        ...
        ...
    
        return F;
    }
    

    현재 우리의 관계는 함수 생성 시 설정된 [[[scope]]이라는 속성입니다.
    이 코드는 그림으로 분석됩니다.
    
    lex() //'lexical'
    function lex() {
        console.log('lexical')
    }
    
  • 운행 상하문 초기화: 전역 운행 환경을 만들고 그것을 운행 창고 맨 위에 놓아서 현재 운행 상하문으로 바꿉니다.
    /**
     *          
     */
     
    var globalExecutionContext = new ExecutionContext();
    globalExecutionContext.LexicalEnvironment = GlobalEnvironment;
    globalExecutionContext.VariableEnvironment = GlobalEnvironment;
    globalExecutionContext.ThisBinding = globalobject;
    
    Runtime.push(globalExecutionContext);
    
    //   Runtime
    Runtime = {
        executionContextStack: [globalExecutionContext];
    };
    
    이때 운행 창고는 이렇게 보입니다.
  • var 성명과 함수 성명은scan 해석 코드를 스캔하여 함수 성명function lex () {console.log ('lexical')}:
    /**
     *          
     */
    var funname = lex;
    var funcbody = "console.log('lexical')";
    var argumentlist = [];
    
    //currentLexicalEnvironment            GlobalEnvironment
    var currentLexicalEnvironment = Runtime.getRunningExecutionContext().VariableEnvironment;
    var fo = FunctionCreate(argumentlist,funcbody,currentLexicalEnvironment,strict) //currentLexicalEnvironment               [[scope]]。
    
    currentLexicalEnvironment.EnvironmentRecord.initialize('lex',fo);
    
    
    이럴 때 이렇게 보입니다:
  • 실행 코드 문:
  • lex():lex를 먼저 해석한 다음lex를 실행한다:
  • /**
     *          
     */
    var fun = Runtime.getRunningExecutionContext().LexicalEnvironment.EnvironmentRecord.getValue('lex');
    //     fun,      F [[call]]    。   。
    

    함수 표현식


    함수 표현식은 두 가지입니다.
    //funcOne()//  ,
    //funcTwo()//  
    var funcOne = function funname(){ //       :               
        console.log('One');
        console.log(funname)
    }
    
    var funcTwo = function () { //       
        console.log('Two')
    }
    
    funcOne()// 'One' 'ƒ funname(){console.log('One');console.log(funname)}'
    funname()//Uncaught ReferenceError: funname is not defined
    
    

    이 코드에서 언급해야 할 사항은 다음과 같습니다.
    var funcOne = function funname(){ 
        console.log('One');
        console.log(funname)
    }
    

    이 전체는 함수 표시식이고 등호 오른쪽function funname () {...}함수 표현식입니다. var funcTwo = function() {...}같은 도리.
    표현식이란 코드를 실행할 때 실행되는 것이다. 상기 코드 세그먼트는 값을 부여하기 전에 함수 표현식을 실행한 다음에 표현식의 실행 결과를 변수funcOne과funcTwo에 각각 부여한다.funcOne과funcTwo는 일반적인 var 성명의 변수로 증가하지만undefined로 초기화됩니다.따라서 값을 부여하기 전에 호출이 잘못될 수 있습니다. 왜냐하면 undefined는 함수가 아니기 때문입니다.
    그래서 우리의 운행 모델에서
             =          + var         scan +     ;
    

    함수 표현식은 '집행문' 단계에서 함수를 만들기 때문에 '향상된 현상' 이 없습니다.
    정확히 말하면 함수를 호출하려면 반드시 그것을 적용해야 하기 때문에 함수 표현식으로 만든 함수를 호출하려면 변수를 인용해야 한다. 그러나 변수는 상승하고 값은undefined이지만 값 부여 동작은 상승하지 않는다. 함수 표현식은 표현식이 실행될 때만 함수를 만들 수 있다.
    명명된 함수 표현식과 함수 성명은 약간 비슷하게 보인다.
    function funndec(){ 
        console.log('Declarations');
    }
    
    var funcOne = function funname(){ //       
        console.log('Expressions');
        console.log(funname);//"function funname(){console.log('Expressions'); console.log(funname);}"
    }
    
    funndec()//Declarations
    funname()//error
    
    

    그러나 함수 성명에 대해서는 함수 밖에서 호출할 수 있지만, 함수 표현식에 대해서는 함수 외에는 사용할 수 없고, 함수 내부에서만 사용할 수 있다.어떻게 이럴 수가 있지?
    명명 함수 표현식의 함수 생성과 함수 성명에 차이가 있음을 설명합니다.우리는 그림으로 그 차이를 설명한다.

    명명 함수 표현식

    function funndec(){ 
        console.log('Declarations');
    }
    
    var funcOne = function funname(){ //       
        console.log('Expressions');
        console.log(funname);//"function funname(){console.log('Expressions'); console.log(funname);}"
    }
    
    funndec()//Declarations
    funname()//error
    
    
  • 운행 상하문 초기화 역시 전역 운행 상하문을 먼저 만든다.
        /**
         *          
         */
        var globalExecutionContext = new ExecutionContext();
        globalExecutionContext.LexicalEnvironment = GlobalEnvironment;
        globalExecutionContext.VariableEnvironment = GlobalEnvironment;
        globalExecutionContext.ThisBinding = globalobject;
        
        Runtime.push(globalExecutionContext);
        
        //   Runtime
        Runtime = {
            executionContextStack: [globalExecutionContext];
        };
    
  • var 선언 및 함수 선언 스캔scan:
  • 함수 설명 찾기 function funndec () {console.log ('Declarations');},현재 문법 환경에 등록하기:
    /**
     *          
    */
    var funname = 'funndec';
    var funcbody = "console.log('Declarations');";
    var argumentlist = [];
    
    //currentLexicalEnvironment            GlobalEnvironment
    var currentLexicalEnvironment = Runtime.getRunningExecutionContext().VariableEnvironment;
    var fo = FunctionCreate(argumentlist,funcbody,currentLexicalEnvironment,strict) //currentLexicalEnvironment               [[scope]]。
    
    currentLexicalEnvironment.EnvironmentRecord.initialize(funname,fo);//
    
    
    
  • var 성명: var funcOne을 찾았습니다. 현재 문법 환경에 등록하는 작업을 실행합니다.
        currentLexicalEnvironment.set('funcOne') //funcOne=undefined
    
  • 이럴 때가 왔다.
  • 실행문: 대입문 "funcOne = function funname () {...}"을 만났습니다.함수 표현식 function funname 실행 () {...}:
        /**
         *          
        */
       var funname = 'funname';
       var funcbody = "console.log('Expressions'); console.log(funname);";
       var argumentlist = [];
      //              ,            GlobalEnvironment
       var currentLexicalEnvironment = Runtime.getRunningExecutionContext().LexicalEnvironment;
       //          
       var newLexicalEnviroment = new LexicalEnvironment();
       //  newLexicalEnviroment outer       
       newLexicalEnviroment.outer = currentLexicalEnvironment;
       //  newLexicalEnviroment      
       var fo = FunctionCreate(argumentlist,funcbody,newLexicalEnviroment,strict//          )
       // newLexicalEnviroment          
       newLexicalEnviroment.EnvironmentRecord.initialize(funname,fo);
         fo
       
    

  • 이때 보면 다음과 같다.
    약간 복잡하다. 사실 유일하게 함수 성명과 차이점은 함수 성명의 함수 창설 과정은 현재 실행 중인 상하의 문법 환경을 사용하고, 명명 함수 표현식의 함수 창설 과정은 현재 실행 중인 상하의 문법 환경을 사용하기 전에 새로운 문법 환경을 추가하고outer를 통해 현재 실행 중인 상하의 문법 환경과 연결시킨다.또한 자신의 문법 환경에 함수 이름에 대한 귀속funname을 추가합니다. 함수 표현식에서 자신을 호출할 수 있도록 하기 위해서입니다. funname은 함수 외에 정의되지 않았기 때문에 전역적으로 funname () 를 호출하면 오류가 발생합니다./Uncaught Reference Error: funname is not defined.
    다음은 호출문을 실행하는 것입니다.
    funndec()//Declarations
    funname()//error
    

    호출에 대한 자세한 내용은 익명 함수 표현식의 함수 생성과 new Function 방식의 함수 생성을 살펴보겠습니다

    익명 함수 표현식


    익명 함수 표현식은 창설 시기와 함수 성명이 다른 것을 제외하고 창설 과정은 함수 성명과 같다.

    함수 만들기


    new Function(arg1,arg2,...,argn,body)으로 함수를 만드는 과정은 위의 함수 표현식과 유사하다. 함수를 만드는 데 사용하는 scope는 전역 어법 환경(glbal enviroment)을 직접 사용하고 현재 실행 상하문에 관계없이 전역 어법 환경(glbal enviroment)을 일률적으로 취한다.약간 비슷하다.
    /**
     *          
     */
    var argumentlist = [arg1,arg2,...,argn];
    var funbody = body;
    var fo = FunctionCreate(argumentlist,funbody,glbalenviroment,strict);
    

    따라서 함수 내에서 new Function으로 생성된 함수는 글로벌 변수에만 액세스할 수 있습니다.따라서 new Function을 사용하여 함수를 만드는 것은 글로벌 환경에서 함수를 만드는 것과 같습니다.

    [[[scope]] 속성


    함수 생성 과정을 보면 함수가 태어나자마자 [[[scope]] 속성이 붙는데 이 속성은 함수를 만들 때의 문법 환경(Lexical Enviroment)을 저장합니다.함수'선천적'의 작용역으로 정적이며 함수 생성은 함수 체내에 저장된다.
    필자처럼 일생 동안의 환경은 바로 복건성이다. 앞으로 필자가 어디에 가든지 항상'호건'발음을 가진다. 이것은 태어날 때 환경이 나에게 미친 영향이다.
    함수도 만들 때 당시의 문법 환경을 가지고 있기 때문에 앞으로 함수가 어디로 가든지 (어디에서 호출하든지) 창설할 때 가지고 있는 문법 환경에 접근할 수 있다.
    기왕 함수에'선천적'의 작용역이 있는 이상'후천적'의 작용역도 있다는 뜻인가?
    네, 다음 편-함수 호출에서 다시 이야기합시다.

    총결산


    서로 다른 상황에서 함수를 만들 때의 [[[scope]] 속성이 어떤지 정리하고 이 속성은 다음에 또 사용될 수 있기 때문에 다음과 같이 강조한다.

    함수 설명


    함수 표현식


    익명 함수 표현식


    명명 함수 표현식


    new Function


    전재 대상:https://juejin.im/post/5c05f352e51d45480061afe5

    좋은 웹페이지 즐겨찾기