나는 이것을 알지 못할 것입니다. 집에 가고 농장.
코드 사본은 다음과 같습니다.
thisibject [key] 삭제
또는
thisisobject.key를 삭제하십시오
그건 그렇고, 삭제 사용에 대해 이야기합시다
몇 주 전, 나는 Stoyan Stefanov의 객체 지향 JavaScript 책을 읽을 기회가있었습니다. 이 책은 아마존 (12 리뷰, 5 개의 별)에서 높은 평가를 받았으므로 권장되는 책인지 궁금해서 기능 장을 읽기 시작했습니다. 이 책이 사물을 설명하는 방식에 정말 감사하며, 예는 매우 아름답고 점진적으로 구성되어 있으며 초보자 조차도이 지식을 쉽게 마스터 할 수있는 것 같습니다. 그러나 거의 즉시, 나는 기능적 기능을 삭제하는 장 전체에서 흥미로운 오해를 발견했습니다. 다른 오류 (예 : 함수 선언과 함수 표현식의 차이)가 있지만 현재는 논의하지 않을 것입니다.
이 책은 다음과 같이 주장합니다.
"이 기능은 정상 변수처럼 취급됩니다. 다른 변수로 복사하거나 삭제할 수도 있습니다." 이 설명에 예제가 첨부되어 있습니다.
코드 사본은 다음과 같습니다.
var sum = function (a, b) {return a + b;}
var add = sum;
합계를 삭제하십시오
진실
합성 합;
"한정되지 않은"
누락 된 세미콜론을 무시하십시오.이 코드의 오류가 어디에 있는지 알 수 있습니까? 분명히, 오류는 합계 변수를 삭제하는 작업이 성공하지 못한다는 것입니다. 삭제 된 표현식은 true를 반환하지 않아야하며 합계는 "정의되지 않은"을 반환해서는 안됩니다. 이 모든 것은 JavaScript에서 변수를 삭제하는 것이 불가능하기 때문입니다. 적어도 이러한 선언 방식에서는 불가능합니다.
그렇다면이 예에서 정확히 무슨 일이 있었습니까? 버그입니까? 아니면 특별한 사용법? 아마. 이 코드는 실제로 Firebug 콘솔의 실제 출력이며 Stoyan은이를 빠른 테스트를위한 도구로 사용해야합니다. Firebug가 다른 삭제 규칙을 따르는 것과 거의 같습니다. Stoyan이 타락하게 된 것은 Firebug입니다! 그렇다면 여기서 정확히 무슨 일이 있었습니까?
이 질문에 대답하기 전에 먼저 삭제 연산자가 JavaScript에서 어떻게 작동하는지 이해해야합니다. 정확히 삭제할 수 있고 삭제할 수없는 것은 무엇입니까? 오늘, 나는 이것을 자세히 설명하려고 노력할 것이다. 우리는 Firebug의 "이상한"행동을보고 그것이 이상하지 않다는 것을 깨달을 것입니다. 우리는 변수, 기능, 속성에 값을 할당하고 삭제하는 장면 뒤에 숨겨져있는 것에 더 깊이 파고들 것입니다. 우리는 브라우저 호환성과 가장 악명 높은 버그를 살펴볼 것입니다. 또한 ES5의 엄격한 패턴과 삭제 연산자의 동작이 어떻게 변화하는지 논의합니다.
나는 JavaScript와 ecmascript를 교환 할 것입니다. 둘 다 ECMAScript를 의미합니다 (Mozilla의 JavaScript 구현이 분명하지 않는 한).
예상대로, 인터넷에서 삭제에 대한 설명은 상당히 거의 없습니다. MDC 기사는 아마도 가장 좋은 자료 일 것입니다. 그러나 불행히도 주제에 대한 흥미로운 세부 사항이 부족합니다. 이상하게도 잊혀진 것 중 하나는 Firebug의 이상한 표현의 이유입니다. 그리고 MSDN 참조는 이러한 측면에서 거의 쓸모가 없습니다.
이론
따라서 왜 객체의 속성을 삭제할 수 있습니까?
코드 사본은 다음과 같습니다.
var o = {x : 1};
황소 삭제; // 진실
황소; // 한정되지 않은
그러나 이렇게 선언 된 개체는 삭제할 수 없습니다.
코드 사본은 다음과 같습니다.
var x = 1;
x 삭제; // 거짓
엑스; // 1
또는 기능 :
코드 사본은 다음과 같습니다.
함수 x () {}
x 삭제; // 거짓
유형 X; // "기능"
참고 : 속성을 삭제할 수없는 경우 삭제 연산자는 False 만 반환합니다.
이를 이해하려면 먼저 변수 인스턴스 및 속성 속성에 대한 이러한 개념을 마스터해야합니다. 이러한 개념은 불행히도 JavaScript 책에서 거의 언급되지 않습니다. 다음 몇 단락에서 이러한 개념을 간단히 검토하려고합니다. 이러한 개념은 이해하기 어렵습니다! "이러한 일이 왜 이런 식으로 작동하는지"상관하지 않으면이 장을 건너 뛰십시오.
코드 유형 :
ECMAScript에는 3 가지 유형의 실행 코드가 있습니다 : 글로벌 코드, 기능 코드 및 평가 코드. 이러한 유형은 이름 측면에서 다소 자기 설명이 적습니다. 여기에 간단한 개요가 있습니다.
소스 코드가 프로그램으로 간주되면 글로벌 환경에서 실행되며 글로벌 코드로 간주됩니다. 브라우저 환경에서 스크립트 요소의 내용은 일반적으로 프로그램으로 해석되므로 글로벌 코드로 실행됩니다.
함수에서 직접 실행되는 모든 코드는 분명히 함수 코드로 간주됩니다. 브라우저에서 이벤트 속성의 내용 (예 : <p onclick = "...">)은 일반적으로 함수 코드로 해석됩니다.
마지막으로, 내장 기능 평가에 적용되는 코드 텍스트는 평가 코드로 해석됩니다. 곧 우리는 왜이 유형이 특별한 지 알아볼 것입니다.
실행 컨텍스트 :
ECMAScript 코드가 실행되면 일반적으로 특정 실행 컨텍스트에서 발생합니다. 실행 컨텍스트는 다소 추상 엔티티 개념으로, 범위와 가변 인스턴스의 작동 방식을 이해하는 데 도움이됩니다. 세 가지 실행 가능한 코드 각각에 대해 이에 해당하는 실행 컨텍스트가 있습니다. 함수가 실행되면 "프로그램 제어는 함수 코드의 실행 컨텍스트에 들어갑니다"라고 말합니다. 글로벌 코드가 실행되면 프로그램 제어는 글로벌 코드의 실행 컨텍스트에 들어갑니다.
보시다시피 실행 컨텍스트는 논리적으로 스택을 형성 할 수 있습니다. 먼저, 글로벌 코드와 자체 실행 컨텍스트가있을 수 있으며,이 코드는 (함수) 실행 컨텍스트와 함께 함수를 호출 할 수 있습니다. 이 함수는 다른 함수 등을 호출 할 수 있습니다. 함수를 재귀 적으로 호출하더라도 호출 될 때마다 새로운 실행 컨텍스트에 입력됩니다.
활성 객체 (활성화 객체) / 변수 객체 :
각 실행 컨텍스트에는 이와 관련된 소위 변수 객체가 있습니다. 실행 컨텍스트와 유사하게, 가변 객체는 가변 인스턴스를 설명하는 데 사용되는 메커니즘 인 추상 엔티티입니다. 흥미롭게도 소스 코드에 선언 된 변수 및 함수는 일반적 으로이 변수 객체에 속성으로 추가됩니다.
프로그램 제어가 글로벌 코드의 실행 컨텍스트에 들어가면 전역 객체가 변수 객체로 사용됩니다. 이것이 바로 기능 변수가 글로벌이 글로벌 객체 속성이 된 이유입니다.
코드 사본은 다음과 같습니다.
/ *`이것은 글로벌 범위에있을 때 '이것은'글로벌 객체를 말합니다. */
var global_object = this;
var foo = 1;
Global_Object.foo; // 1
foo === global_object.foo; // 진실
함수 바 () {}
Typeof global_object.bar; // "기능"
global_object.bar === bar; // 진실
자, 글로벌 변수는 글로벌 객체의 속성이되지만 로컬 변수 (함수 코드에 정의 된 변수)는 어떻게됩니까? 실제로, 그것들은 매우 유사하게 행동합니다 : 변수 객체 (가변 객체)의 속성이됩니다. 유일한 차이점은 기능 코드에서 가변 객체가 전역 객체가 아니라 소위 활성화 객체라는 것입니다. 활성 개체는 함수 코드의 실행 컨텍스트에 들어갈 때마다 생성됩니다.
함수 코드에 선언 된 변수와 함수만이 활성 객체의 속성이 될 수는 없습니다. 또한 각 함수 매개 변수 (해당 공식 매개 변수에 해당하는 이름) 및 특수 인수 객체 (인수 이름)에서도 발생합니다. 활성 객체는 내부 설명 메커니즘이며 프로그램 코드에서는 액세스 할 수 없습니다.
코드 사본은 다음과 같습니다.
(기능 (foo) {
var bar = 2;
함수 baz () {}
/*
추상적 인 용어로
특수`arguments '객체는 함수의 활성화 객체를 포함하는 속성이됩니다.
activation_object.arguments; // 인수 객체
... 인수`foo` :
activation_object.foo; // 1
...뿐만 아니라 가변`bar ':
activation_object.bar; // 2
... 로컬로 선언 된 기능뿐만 아니라 :
typeof activation_object.baz; // "기능"
*/
}) (1);
마지막으로, 평가 코드에 선언 된 변수는 발신자 컨텍스트에서 가변 객체의 속성이됩니다. 평가 코드는 단순히이를 호출하는 코드의 실행 컨텍스트에서 가변 객체를 사용합니다.
코드 사본은 다음과 같습니다.
var global_object = this;
/*`foo`는 컨텍스트 변수 객체를 호출하는 속성으로 생성됩니다.
이 경우 글로벌 객체 */
평가 ( 'var foo = 1;');
Global_Object.foo; // 1
(기능(){
/*`bar '는 컨텍스트 변수 객체를 호출하는 속성으로 생성됩니다.
이 경우 함수를 포함하는 활성화 객체 */
평가 ( 'var bar = 1;');
/*
추상적 인 용어로
activation_object.bar; // 1
*/
}) ();
속성 속성
우리는 거의 여기 있습니다. 이제 우리는 변수 (속성이 된)에서 무슨 일이 일어나고 있는지 잘 알고 있으므로 이해해야 할 유일한 나머지 개념은 속성 속성입니다. 각 속성에는 0 개 이상의 속성이있을 수 있으며,이 세트는 다음 세트에서 선택됩니다 : Readonly, Dontenum, DontDelete 및 내부. 속성에 존재하거나 존재하지 않는 기능인 깃발로 생각할 수 있습니다. 오늘 토론을 위해 우리는 DontDelete에만 관심이 있습니다.
선언 된 변수와 함수가 변수 객체 (또는 기능 코드의 활성 객체 또는 글로벌 코드의 글로벌 객체)의 속성이되면 이러한 속성은 DontDelete 속성 속성으로 생성됩니다. 그러나 명시 적 (또는 암시 적) 속성은 dontdelete 속성에 포함되지 않습니다. 그렇기 때문에 일부 속성을 삭제할 수 있지만 다른 속성을 삭제할 수는 없습니다.
코드 사본은 다음과 같습니다.
var global_object = this;
/*`foo`는 글로벌 객체의 속성입니다.
변수 선언을 통해 생성되며 DontDelete 속성이 있습니다.
이것이 삭제할 수없는 이유입니다. */
var foo = 1;
foo 삭제; // 거짓
foo 유형; // "숫자"
/*`bar '는 글로벌 객체의 속성입니다.
함수 선언을 통해 생성되므로 DontDelete 속성이 있습니다.
이것이 삭제할 수없는 이유입니다. */
함수 바 () {}
막대 삭제; // 거짓
막대 타입; // "기능"
/*`baz`는 또한 글로벌 객체의 속성입니다.
그러나 속성 할당을 통해 생성되므로 DontDelete 속성이 없습니다.
이것이 삭제 될 수있는 이유입니다. */
global_object.baz = 'blah';
global_object.baz 삭제; // 진실
Typeof global_object.baz; // "한정되지 않은"
내장 객체 및 DontDelete
따라서 이것은 전부입니다 (dontdelete) :이 속성을 삭제할 수 있는지 여부를 제어하는 재산의 특수 재산입니다. 일부 내장 객체는 DontDelete를 포함하도록 지정되므로 삭제할 수 없습니다. 예를 들어, 특별한 인수 변수 (또는 지금 알고 있듯이 활성 객체의 속성)는 dontdelete입니다. 함수 인스턴스의 길이 속성에는 DontDelete 속성도 있습니다.
코드 사본은 다음과 같습니다.
(기능(){
/ * 'arguments'는 삭제할 수 없습니다.
인수 삭제; // 거짓
인수 유형; // "물체"
/* 함수의 '길이'를 삭제할 수 없습니다. 또한 dontdelete */
함수 f () {}
f.length 삭제; // 거짓
F.length 형태; // "숫자"
}) ();
함수 매개 변수에 해당하는 속성에는 설립 이후 DontDelete 기능이 있으므로 삭제할 수 없습니다.
코드 사본은 다음과 같습니다.
(기능 (foo, bar) {
foo 삭제; // 거짓
foo; // 1
막대 삭제; // 거짓
술집; // 'blah'
}) (1, 'blah');
선언되지 않은 과제 :
당신은 또한 노출되지 않은 과제가 글로벌 오브젝트 앞에이 스코프 체인의 다른 곳에서 발견되지 않는 한 글로벌 객체에 속성을 생성한다는 것을 기억할 수도 있습니다. 그리고 이제 우리는 속성 할당과 가변 선언의 차이를 알고 있습니다. 후자는 dontdelete 속성을 설정하지만 전자는 그렇지 않습니다. 선언되지 않은 과제가 왜 삭제 가능한 속성을 생성하는지 분명해야합니다.
코드 사본은 다음과 같습니다.
var global_object = this;
/* 변수 선언을 통해 글로벌 속성 생성; 속성은 dontdelete */
var foo = 1;
/* 선언되지 않은 할당을 통해 글로벌 속성을 만듭니다. 속성에는 dontdelete */
바 = 2;
foo 삭제; // 거짓
foo 유형; // "숫자"
막대 삭제; // 진실
막대 타입; // "한정되지 않은"
참고 : 속성이 생성 될 때 속성이 결정되며 후속 할당은 기존 속성의 속성을 수정하지 않습니다. 이 차이를 이해하는 것이 매우 중요합니다.
코드 사본은 다음과 같습니다.
/ *`foo`는 dontdelete */가있는 속성으로 만들어졌습니다.
함수 foo () {}
/* 나중에 할당은 속성을 수정하지 않습니다. dontdelete가 아직 거기에 있습니다! */
foo = 1;
foo 삭제; // 거짓
foo 유형; // "숫자"
/* 그러나 존재하지 않는 속성에 할당하면
빈 속성으로 해당 속성을 만듭니다.
this.bar = 1;
막대 삭제; // 진실
막대 타입; // "한정되지 않은"
Firebug 혼동 :
Firebug에서는 어떻게됩니까? 콘솔에서 선언 된 변수를 삭제할 수있는 이유는 무엇입니까? 이것이 우리가 전에 배운 것과 상반되지 않습니까? 앞서 말했듯이, Eval Code는 변수 선언에 직면 할 때 특별한 성능을 가지고 있습니다. Eval에 선언 된 변수는 실제로 DontDelete 속성이없는 속성으로 생성됩니다.
코드 사본은 다음과 같습니다.
평가 ( 'var foo = 1;');
foo; // 1
foo 삭제; // 진실
foo 유형; // "한정되지 않은"
마찬가지로, 기능 코드에서 호출 될 때 :
코드 사본은 다음과 같습니다.
(기능(){
평가 ( 'var foo = 1;');
foo; // 1
foo 삭제; // 진실
foo 유형; // "한정되지 않은"
}) ();
이것은 소방대 비정상 행동의 기초입니다. 콘솔의 모든 텍스트는 글로벌 또는 기능 코드가 아닌 평가 코드로 구문 분석 및 실행됩니다. 분명히, 여기에 선언 된 모든 변수는 결국 dontdelete 속성이없는 속성이되므로 모두 쉽게 삭제할 수 있습니다. 글로벌 코드와 Firebug 콘솔의 차이점을 이해해야합니다.
평가를 통해 변수 삭제 :
ECMAScript의 또 다른 측면과 함께이 흥미로운 평가 동작은 기술적으로 "삭제 불가능한"속성을 삭제할 수 있습니다. 함수 선언의 한 가지는 동일한 실행 컨텍스트에서 동일한 이름으로 변수를 재정의 할 수 있다는 것입니다.
코드 사본은 다음과 같습니다.
함수 x () {}
var x;
유형 X; // "기능"
함수 선언이 어떻게 우선 순위를 얻고 같은 이름으로 변수를 덮어 쓰는 방법 (즉, 변수 객체의 동일한 속성). 이는 변수 선언 후에 함수 선언이 인스턴스화되어이를 덮어 쓸 수 있기 때문입니다 (변수 선언). 함수 선언은 속성의 값을 대체 할뿐만 아니라 해당 속성의 속성을 대체합니다. Eval을 통해 함수를 선언하면 해당 함수는 원본 (대체) 속성의 속성을 자체 속성으로 바꿔야합니다. 또한 Eval을 통해 선언 된 변수는 dontdelete 속성없이 속성을 작성하기 때문에이 새로운 기능을 인스턴스화하면 속성에서 기존의 dontDelete 속성을 실제로 제거하여 속성을 삭제할 수 있습니다 (그리고 분명히 새로 생성 된 함수를 가리 킵니다).
코드 사본은 다음과 같습니다.
var x = 1;
/ * 삭제할 수 없음,`X`는 dontDelete */
x 삭제; // 거짓
유형 X; // "숫자"
평가 ( 'function x () {}');
/ *`x` 속성은 이제 참조 기능을 참조하며 dontdelete */가 없어야합니다.
유형 X; // "기능"
x 삭제; //`true '여야합니다
유형 X; // "정의되지 않은"
불행히도,이 "기만"은 현재 어떤 구현에서도 작동하지 않습니다. 어쩌면 여기에 무언가를 놓치거나 행동이 너무 모호하다고 어쩌면 구현자가 눈치 채지 못할 수도 있습니다.
브라우저 호환성 :
이론적으로 일이 어떻게 작동하는지 이해하는 것이 유용하지만 연습이 가장 중요한 것입니다. 브라우저는 변수/속성을 작성/삭제할 때 표준을 따릅니다. 대답은 다음과 같습니다. 대부분의 경우 그렇습니다.
글로벌 코드, 기능 코드 및 평가 코드의 테스트를 포함하여 삭제 연산자와 브라우저 호환성을 테스트하기 위해 간단한 테스트 세트를 작성했습니다. 테스트 세트는 삭제 연산자의 리턴 값과 속성 값이 실제로 삭제되는지 확인합니다. 삭제의 반환 값은 실제 결과만큼 중요하지 않습니다. 삭제가 false 대신 true를 반환하면 중요하지 않으며 중요한 것은 DontDelete 속성을 가진 속성이 삭제되지 않으며 그 반대도 마찬가지입니다.
현대식 브라우저는 일반적으로 상당히 호환됩니다. 앞에서 언급 한 평가 기능 외에도 다음 브라우저는 Opera 7.54+, Firefox 1.0+, Safari 3.1.2+, Chrome 4+의 모든 테스트 세트를 통과했습니다.
Safari 2.X 및 3.0.4는 함수 매개 변수를 삭제할 때 문제가 있습니다. 이러한 속성은 DontDelete없이 생성되는 것처럼 보이므로 삭제할 수 있습니다. Safari 2.x는 더 많은 문제가 있습니다. 삭제되지 않은 변수 삭제 (예 : 삭제 1)는 예외를 던집니다. 함수 선언은 삭제 가능한 속성을 만듭니다 (그러나 이상하게도 변수 선언은 그렇지 않습니다). Eval의 변수 선언은 비 지분이됩니다 (그러나 함수 선언은 삭제할 수 있습니다).
Safari와 유사하게 Konqueror (4.3이 아닌 3.5)는 참조되지 않은 유형 (예 : Delete 1)을 삭제할 때 예외를 발생시키고 기능 변수를 잘못 사용할 수있게합니다.
번역가 노트 :
나는 Chrome, Firefox 및 IE의 최신 버전을 테스트했으며 기본적으로 23과 24를 제외한 다른 모든 패스가 실패하는 상황을 유지했습니다. 동시에 UC와 일부 모바일 브라우저를 테스트했습니다. 실패 15 및 16 인 Nokia E72의 내장 브라우저를 제외하고 다른 내장 브라우저는 대부분 데스크탑 브라우저와 동일합니다. 그러나 BlackBerry Curve 8310/8900의 내장 브라우저는 23을 통과 할 수 있다는 점을 언급 할 가치가 있습니다.
Gecko dontdelete 버그 :
Gecko 1.8.x 브라우저 -Firefox 2.X, Camino 1.X, Seamonkey 1.X 등 - 매우 흥미로운 버그를 보여줍니다. 부동산의 명시 적 할당은 변수 선언 또는 함수 선언을 통해이 속성이 생성 되더라도 DontDelete 속성을 제거 할 것입니다.
코드 사본은 다음과 같습니다.
함수 foo () {}
foo 삭제; // false (예상대로)
foo 유형; // "function"(예상대로)
/ * 이제 숙소에 명시 적으로 할당 */
this.foo = 1; // dontDelete 속성을 잘못 지우십시오
foo 삭제; // 진실
foo 유형; // "한정되지 않은"
/ * 부동산을 암시 적으로 할당 할 때는 발생하지 않습니다 */
함수 바 () {}
바 = 1;
막대 삭제; // 거짓
막대 타입; // "숫자"(과제가 부동산 대체되었지만)
놀랍게도, Internet Explorer 5.5-8은 참조되지 않은 유형 (예 : 삭제 1)을 삭제하는 것이 예외 (오래된 사파리와 마찬가지로)를 제외한다는 점을 제외하고는 전체 테스트 세트를 통과했습니다. 그러나 IE에는 더 심각한 버그가 있으며, 이는 분명하지 않습니다. 이러한 버그는 글로벌 객체와 관련이 있습니다.
즉, 버그 :
이 장 전체는 인터넷 익스플로러 버그에 대해 이야기합니까? 우와! 놀랍습니다!
IE (IE 6-8)에서 다음 표현식은 (글로벌 코드로 실행될 때) 예외를 던집니다.
this.x = 1;
x 삭제; // TypeError : 객체는이 작업을 지원하지 않습니다
이것은 또한 다른 예외를 던질 것이며, 이로 인해 상황이 더욱 흥미로워집니다.
var x = 1;
this.x; // typeerror : 'this.x'를 삭제할 수 없습니다.
이는 IE에서 보인다. 글로벌 코드의 변수 선언은 글로벌 오브젝트에 속성을 생성하지 않습니다. 할당에 의해 속성을 생성 한 다음 (this.x = 1) 다음 X를 삭제하여 삭제하면 오류가 발생합니다. 선언 (var x = 1)을 통해 속성을 만들고 나중에 삭제하면 다른 오류가 발생합니다.
그러나 그게 전부는 아닙니다. 명시 적 할당으로 속성을 만드는 것은 실제로 삭제 될 때 항상 예외를 발생시킵니다. 여기에는 오류가있을뿐만 아니라 생성 된 속성에는 DontDelete 속성이있는 것 같습니다. 물론 그렇지 않아야합니다.
this.x = 1;
this.x; // TypeError : 객체는이 작업을 지원하지 않습니다
유형 X; // "숫자"(여전히 존재하지만 삭제되지 않았습니다!)
x 삭제; // TypeError : 객체는이 작업을 지원하지 않습니다
유형 X; // "번호"(다시 삭제되지 않음)
이제, 우리는 즉, 선언되지 않은 과제 (전역 객체에서 속성이 만들어 져야 함)가 묘사 가능한 속성을 생성한다고 생각할 것입니다.
x = 1;
x 삭제; // 진실
유형 X; // "한정되지 않은"
그러나 글로벌 코드 (삭제) 에서이 참조를 통해이 속성을 삭제하면 비슷한 오류가 나타납니다.
x = 1;
this.x; // typeerror : 'this.x'를 삭제할 수 없습니다.
이 동작을 요약하려면 this.x를 사용하여 글로벌 코드에서 변수를 삭제하는 것은 결코 성공하지 못하는 것 같습니다. 질문의 속성이 명시 적 할당 (this.x = 1)에 의해 생성되면 삭제는 오류를 던집니다. 속성이 선언되지 않은 할당 (x = 1) 또는 선언 (var x = 1)에 의해 만들어지면 다른 오류가 발생합니다.
반면에 x 삭제 x 삭제는 명시 적 할당에 의해 속성이 생성 된 경우에만 오류가 발생해야합니다. this.x = 1. 선언 (var x = 1)에 의해 속성이 생성되면 삭제 작업이 발생하지 않으며 삭제 작업이 올바르게 반환됩니다. 선언되지 않은 할당 (x = 1)에 의해 속성이 생성되면 삭제 작업은 예상대로 작동합니다.
9 월 에이 문제에 대해 다시 생각했습니다. 개렛 스미스는 즉
"글로벌 변수 객체는 jscript 객체로 구현되며 글로벌 객체는 호스트에 의해 구현됩니다."
Garrett은 Eric Lippert의 블로그 항목을 참조로 사용했습니다.
우리는 일부 테스트를 구현 하여이 이론을 어느 정도 확인할 수 있습니다. 이 및 창은 동일한 객체 (=== 연산자를 신뢰할 수있는 경우)를 가리키는 것처럼 보이지만 변수 객체 (함수 선언이 위치한 객체)는이 점과 다릅니다.
코드 사본은 다음과 같습니다.
/ * 글로벌 코드 */
함수 getBase () {return this; }
getBase () === this.getBase (); // 거짓
this.getBase () === this.getBase (); // 진실
window.getBase () === this.getBase (); // 진실
window.getBase () === getBase (); // 거짓
오해:
왜 그런 식으로 일하는 이유를 이해하는 아름다움은 과소 평가되지 않아야합니다. 인터넷에서 삭제 연산자에 대한 오해를 보았습니다. 예를 들어, stackoverflow (놀랍게도 높은 등급)에 대한 답은 자신있게 설명합니다.
"대상 피연산자가 객체 속성이 아닌 경우 삭제는 작동해야합니다."
이제 우리는 삭제 작업 동작의 핵심을 이해 했으므로이 답변의 오류는 분명해집니다. DELETE는 변수와 속성을 구별하지 않습니다 (실제로 삭제의 경우 모두 참조 유형).
다양한 오해가 서로 반박하는 것을 보는 것도 매우 흥미 롭습니다. 같은 주제에서 한 사람은 먼저 변수 만 삭제하는 경우 (Eval에서 선언되지 않는 한 작동하지 않음), 다른 사람은 삭제 방법에 대한 버그 수정을 제공했지만 기능 코드에서는 변수를 삭제하는 방법에 대한 버그 수정을 제공했습니다.
인터넷에서 JavaScript의 설명에 대해 더주의하십시오. 이상적인 방법은 항상 문제의 본질을 이해하는 것입니다. ;)
삭제 및 호스트 객체 (호스트 객체) :
삭제 알고리즘은 다음과 같습니다.
피연산자가 참조 유형이 아닌 경우 true 반환
객체 에이 이름의 직접적인 속성이 없으면 true를 반환합니다 (우리가 알고 있듯이 객체는 활성 객체 또는 전역 객체 일 수 있습니다).
속성이 존재하지만 dontdelete 속성이 있으면 false를 반환합니다.
다른 경우에는 속성을 삭제하고 true를 반환하십시오
그러나 호스트 객체에서 삭제 연산자의 동작은 예측할 수 없습니다. 그리고이 동작은 실제로 잘못되지 않습니다. (표준), 호스트 객체는 read (내부 [[get] 메소드), 쓰기 (내부 [[put]] 메소드) 및 delete (내부 [[delete]] 메소드와 같은 여러 연산자의 동작을 구현할 수 있습니다. Custom [[Delete]] 행동을위한이 은혜는 호스트 객체를 혼란스럽게 만드는 것입니다.
우리는 특정 객체 (분명히 호스트 객체로 구현되는)가 오류를 던지는 특정 객체를 삭제하는 일부 IE Quirks를 보았습니다. 일부 버전의 Firefox는 Window.location을 삭제할 때 던져집니다. 피연산자가 호스트 객체 인 경우 삭제의 반환 값을 신뢰할 수 없습니다. Firefox에서 무슨 일이 일어나는지 보자 :
코드 사본은 다음과 같습니다.
/ * "ALERT"는`window '의 직접적인 속성입니다 ('hasOwnProperty ') */
window.hasownproperty ( 'Alert'); // 진실
window.alert 삭제; // 진실
typeof window.alert; // "기능"
이 속성이 그러한 결과를 전혀 유발할 이유가 없더라도 window.alert는 true를 반환합니다. 참조로 해결됩니다 (첫 번째 단계에서는 True를 반환하지 않습니다). 이것은 창 객체의 직접적인 속성입니다 (두 번째 단계에서는 true를 반환하지 않습니다). 따라서 Delete가 True를 반환 할 수있는 유일한 경우는 네 번째 단계에 도달하여 실제로 해당 속성을 삭제하는 것입니다. 그러나이 속성은 결코 삭제되지 않습니다.
이 이야기의 도덕은 : 호스트 대상을 신뢰하지 마십시오.
ES5 엄격한 모드 :
그렇다면 엄격한 모드 ecmascript5는 우리에게 무엇을 가져 오는가? 제한 사항이 거의 없습니다. 삭제 연산자의 표현식이 변수, 함수 매개 변수 또는 함수 식별자에 대한 직접 참조 인 경우 구문 오류가 발생합니다. 또한, 속성에 내부 속성 [[configurable]] == false가 있으면 유형 오류가 발생합니다.
코드 사본은 다음과 같습니다.
(기능 (foo) {
"엄격한 사용"; //이 함수 내에서 엄격한 모드를 활성화합니다
var bar;
함수 baz () {}
foo 삭제; // syntaxError (인수 삭제시)
막대 삭제; // syntaxError (변수 삭제시)
BAZ 삭제; // syntaxError (함수 선언으로 생성 된 변수를 삭제할 때)
/ *`function 인스턴스의 길이 '는 {[[configurable]] : false} */
delete (function () {}). 길이; // TypeError
}) ();
또한 노동되지 않은 변수 (또는 해결되지 않은 참조)를 삭제하면 구문 오류가 발생합니다.
"엄격한 사용";
i_dont_exist를 삭제합니다. // syntaxError
선언되지 않은 할당은 엄격한 모드에서 선언되지 않은 변수와 유사하게 동작합니다 (이 시간을 제외하고 구문 오류 대신 견적 오류가 발생합니다) :
"엄격한 사용";
i_dont_exist = 1; // referenceError
지금 이해 한 바와 같이, 변수, 기능 선언 및 매개 변수를 삭제하면 혼란이 너무 많기 때문에 모든 제한은 다소 의미가 있습니다. 삭제 작업을 조용히 무시하는 대신 엄격한 패턴은보다 급진적이고 설명적인 측정을 취합니다.
요약 :
이 블로그 게시물은 결국 꽤 길어 졌기 때문에 Delete를 사용하여 배열 객체를 삭제하는 것과 같은 것에 대해 이야기하지 않을 것입니다. MDC 기사의 특별한 설명을 참조하거나 표준을 읽고 자체 실험을 수행 할 수 있습니다).
다음은 JavaScript에서 삭제 작업이 어떻게 작동하는지에 대한 간략한 요약입니다.
변수 및 함수 선언은 활성 객체 또는 전역 객체의 속성입니다.
속성에는 몇 가지 특성이 있으며 DontDelete는이 속성을 삭제할 수 있는지 여부를 결정하는 속성입니다.
글로벌 또는 기능 코드의 변수 및 함수 선언은 항상 dontdelete 속성으로 속성을 만듭니다.
함수 매개 변수는 항상 활성 객체의 속성이며 dontdelete가 동반됩니다.
Eval Code에서 선언 된 변수 및 함수는 항상 dontdelete없이 속성을 만듭니다.
새로운 속성은 생성 될 때 속성이 없습니다 (물론 DontDelete도 없습니다).
호스트 객체는 삭제 작업에 반응하는 방법을 자체적으로 결정할 수 있습니다.
여기에 설명 된 내용에 더 익숙해 지려면 ECMA-262 3rd Edition 사양을 참조하십시오.
이 기사를 즐기고 새로운 것을 배울 수 있기를 바랍니다. 질문, 제안 또는 수정이 환영합니다.