서문
자바스크립트에서는 범위, 컨텍스트, 클로저, 함수 등이 최고 중의 최고입니다. 초보자 JSers의 경우 고급 수준의 필수 항목입니다. 프론트 엔드 공성 엔지니어의 경우 이러한 본질을 진정시키고 이해해야만 우아한 코드를 작성할 수 있습니다.
이 글은 잊어버리기 쉽고 기본 개념을 다루지 않는 중요한 지식을 요약하는 것을 목표로 합니다. 기초 지식이 낯설다면 "JavaScript 완벽 가이드"를 읽어보세요~
언어 특징 함수 표현
먼저 코드 스니펫을 살펴보세요.
json
{ “prop”: “val” } 이러한 선언은 사용되는 컨텍스트에 따라 JavaScript 개체 리터럴 또는 JSON 문자열일 수 있습니다. 문자열 컨텍스트에서 사용되는 경우(작은따옴표나 큰따옴표로 묶이거나 텍스트 파일에서 읽음) 객체 리터럴 컨텍스트에서 사용되는 경우 객체 리터럴입니다.
시제품
그러나 프로토타입 속성을 제출해도 이미 생성된 객체의 프로토타입에는 영향을 미치지 않습니다(생성자의 프로토타입 속성이 변경되는 경우에만 영향을 받습니다). 즉, 새로 생성된 객체만 새 프로토타입을 갖게 됩니다. 이미 생성된 객체는 여전히 원래의 이전 프로토타입을 참조하여 새 프로토타입을 갖게 됩니다(이 프로토타입은 더 이상 수정할 수 없습니다).
변수 객체 함수 실행 컨텍스트에서는 VO(변수 객체)에 직접 접근할 수 없습니다. 이때 활성화 객체(activation object)가 VO 역할을 합니다. 활성 객체는 함수 컨텍스트에 들어갈 때 생성되고 함수의 인수 속성을 통해 초기화됩니다. Arguments 속성의 값은 Arguments 객체입니다:
•모든 함수 선언(FunctionDeclaration, FD);
•모든 변수 선언(var, VariableDeclaration)
또 다른 전형적인 예:
코드 복사
코드 복사
이 예에서는 함수 객체가 있지만 참조 유형 객체는 없습니다(식별자도 아니고 속성 접근자도 아님). 따라서 this 값은 최종적으로 전역 객체로 설정됩니다.
•첫 번째 예는 명백합니다. 결과적으로 이것이 기본 개체인 foo입니다.
• 두 번째 예에서는 그룹 연산자가 적용되지 않습니다. 위에서 언급한 GetValue와 같은 참조 유형에서 객체의 실제 값을 가져오는 메서드를 생각해 보세요. 이에 따라 그룹 작업이 반환될 때 여전히 참조 유형을 얻습니다. 이것이 바로 this 값이 기본 개체인 foo로 다시 설정되는 이유입니다.
•세 번째 예에서는 그룹 연산자와 달리 할당 연산자가 GetValue 메서드를 호출합니다. 반환된 결과는 함수 객체입니다(참조 유형은 아님). 이는 null로 설정되고 결과가 전역 객체임을 의미합니다.
• 네 번째와 다섯 번째도 마찬가지입니다. 쉼표 연산자와 논리 연산자(OR)가 GetValue 메서드를 호출하고 이에 따라 참조를 잃고 함수를 가져옵니다. 그리고 다시 전역으로 설정하세요.
아시다시피 지역 변수, 내부 함수, 형식 매개변수는 해당 함수의 활성화 개체에 저장됩니다.
스코프 체인
한 가지 중요한 예외는 함수 생성자를 통해 생성된 함수와 관련됩니다.
또한:
컨텍스트에 들어가면 어떻게 되나요? 식별자 "x"와 "y"가 변수 개체에 추가되었습니다. 또한 코드 실행 단계에서 다음과 같이 수정하세요.
•x = 10, y = 10;
•스코프 앞에 {x:20} 객체가 추가됩니다.
•with 내부에서 var 선언이 발견되고 물론 아무것도 없습니다. 컨텍스트를 입력할 때 모든 변수가 구문 분석되고 추가되었기 때문에 생성됩니다.
• 두 번째 단계에서는 변수 "x"만 수정되고 실제로 개체의 "x"가 구문 분석되어 추가됩니다. 스코프 체인 앞의 "x"는 20이고 30이 됩니다.
•파싱된 후 변수 개체 "y"도 수정되었으며 해당 값도 10에서 30으로 변경됩니다.
• 또한 with 문이 완료된 후 해당 특정 개체가 범위 체인에서 제거됩니다(변경된 변수 "x" - 30도 해당 개체에서 제거됨). 즉 범위 체인의 구조가 상태로 복원됩니다. 이전에는 with가 강화되었습니다.
•마지막 두 개의 경고에서 현재 변수 개체의 "x"는 동일하게 유지되고 "y"의 값은 이제 30과 동일하며 with 문 실행 중에 변경되었습니다.
함수
괄호에 관한 질문
다음 질문을 살펴보겠습니다. '함수를 생성한 후 즉시 호출할 때 함수를 괄호로 묶어야 하는 이유는 무엇입니까? '라고 대답하면, 표현문의 제한은 이렇습니다.
표준에 따르면 표현식 문은 코드 블록과 구별하기 어렵기 때문에 중괄호 {로 시작할 수 없습니다. 마찬가지로 함수 선언과 구별하기 어렵기 때문에 함수 키워드로 시작할 수 없습니다. 즉, 생성 직후 즉시 실행되는 함수를 정의하면 다음과 같이 호출합니다.
위의 두 가지 정의에 대해 함수 선언을 사용했는데, 해석할 때 해석기가 오류를 보고하지만 이유는 다양할 수 있습니다. 전역 코드(즉, 프로그램 수준)에 정의된 경우 함수 키워드로 시작하므로 인터프리터는 이를 함수 선언으로 처리합니다. 첫 번째 예에서는 함수 선언에 이름이 없기 때문에 SyntaxError가 발생합니다. (앞서 함수 선언에는 이름이 있어야 한다고 언급했습니다). 두 번째 예에는 정상적으로 생성된 foo라는 함수 선언이 있지만 여전히 구문 오류가 발생합니다. 즉, 표현식이 없는 그룹화 연산자 오류입니다. 이는 실제로 함수 호출에 사용되는 괄호가 아니라 함수 선언 뒤의 그룹화 연산자입니다. 따라서 다음 코드를 선언하면:
표현식을 만드는 가장 간단한 방법은 그룹화 연산자 대괄호를 사용하는 것입니다. 안에 들어가는 내용은 항상 표현식이므로 통역사가 해석할 때 모호함이 없습니다. 이 함수는 코드 실행 단계에서 생성되어 즉시 실행된 후 자동으로 소멸됩니다(참조가 없는 경우)
위 코드는 식을 괄호로 묶은 다음 (1)을 통해 호출하는 코드입니다. 즉시 실행되는 다음 함수의 경우 함수가 이미 표현식의 위치에 있고 파서는 함수 실행 단계에서 생성되어야 하는 FE를 처리하고 있음을 알고 있기 때문에 주변 괄호가 필요하지 않습니다. , 함수가 생성된 직후에 호출되도록 합니다.
보시다시피 foo.bar는 함수가 아닌 문자열입니다. 여기서 함수는 조건부 매개변수를 기반으로 이 속성을 초기화하는 데만 사용됩니다. 즉시 생성되고 호출됩니다.
1. 따라서 "괄호에 대하여"라는 질문에 대한 완전한 답변은 다음과 같습니다.
2. 함수가 표현식 위치에 없는 경우 그룹화 연산자 괄호가 필요합니다. 즉, 수동으로 함수는 FE로 변환됩니다.
3. 파서가 FE를 다루고 있다는 것을 알고 있다면 괄호를 사용할 필요가 없습니다.
자유 변수:
정적 폐쇄 범위:
이론: 범위 체인으로 인해 모든 함수는 클로저입니다(함수 유형에 관계없이 익명 함수, FE, NFE 및 FD는 모두 클로저입니다). 실용적인 관점에서 볼 때 다음 함수는 클로저로 간주됩니다. * 생성된 컨텍스트가 파괴된 경우에도 여전히 존재합니다(예: 내부 함수가 상위 함수에서 반환됨)
* 코드에서 자유 변수
를 참조합니다.마지막으로:
ECMAScript는 프로토타입 기반 위임 상속을 지원하는 객체 지향 언어입니다.