Configurable
을 설명하기 전에 먼저 면접 질문을 살펴보겠습니다.
a = 1; console.log( window.a ); // 1 console.log( delete window.a ); // true console.log( window.a ); // undefined var b = 2; console.log( window.b ); // 2 console.log( delete window.b ); // false console.log( window.b ); // 2
위 질문에서 두 가지 차이점을 볼 수 있습니다. var를 사용하여 변수를 선언하지 않은 경우 delete 키워드를 사용하여 삭제할 수 있고, var를 사용하여 변수를 선언하면 다시 가져오면 값이 정의되지 않습니다. 삭제를 사용하여 삭제할 수 없으며 검색 시 값은 여전히 2입니다.
삭제를 사용하여 변수나 속성을 삭제할 때 삭제에 성공하면 true를 반환하고, 그렇지 않으면 false를 반환합니다. 위의 예에서와 같이 삭제가 변수 a를 삭제할 수 없으면 false를 반환하고, 삭제가 변수 b를 성공적으로 삭제할 수 있으면 true를 반환합니다.
위의 두 가지 상황 외에도 일반적으로 사용되는 다양한 변수 중 삭제로 삭제할 수 있는 변수와 삭제할 수 없는 변수가 있습니다. delete가 왜 그런 결과를 내는지 걱정하지 마세요. 여기서는 반환 값만 살펴보겠습니다.
삭제 배열에서 요소 삭제:
// 使用for~in是循环不到的,直接忽略到该元素 // 使用for()可以得到该元素,但是值是undefined var arr = [1, 2, 3, 4]; console.log( arr ); // [1, 2, 3, 4] console.log( delete arr[2] ); // true,删除成功 console.log( arr ); // [1, 2, undefined, 4]
함수 유형 변수 삭제:
// chrome 不能删除;火狐可以删除 function func(){ } console.log( func ); console.log( delete func ); console.log( func );
획득된 형식 매개변수의 개수인 function.length를 삭제합니다.
function func1(a, b){ } console.log( func1.length ); // 2 console.log( delete func1.length ); // true,删除成功 console.log( func1.length ); // 0
자주 사용하는 변수 삭제:
console.log( delete NaN ); // false,删除失败 console.log( delete undefined );// false console.log( delete Infinity ); // false console.log( delete null ); // true,删除成功
프로토타입의 속성을 삭제하는 대신 프로토타입을 삭제하세요.
function Person(){ } Person.prototype.name = "蚊子"; console.log( delete Person.prototype ); // false,无法删除 console.log( delete Object.prototype ); // false
배열, 문자열의 길이를 삭제하는 경우:
var arr = [1, 2, 3, 4]; console.log( arr.length ); // 4 console.log( delete arr.length ); // false,删除失败 console.log( arr.length ); // 4 var str = 'abcdefg'; console.log( str.length ); // 7 console.log( delete str.length ); // false,删除失败 console.log( str.length ); // 7
obj에서 속성을 삭제하는 경우:
var obj = {name:'wenzi', age:25}; console.log( obj.name ); // wenzi console.log( delete obj.name ); // true,删除成功 console.log( obj.name ); // undefined console.log( obj ); // { age:25 }
인스턴스 객체의 속성을 삭제할 때 삭제를 사용하여 속성을 삭제하면 인스턴스 객체 자체의 속성만 삭제되고 프로토타입의 속성은 삭제할 수 없다는 것을 다음 출력에서 확인할 수 있습니다. 다시 삭제해도 삭제될 수 없습니다. 프로토타입에서 속성이나 속성의 메서드를 삭제하려면 다음과 같이 하세요. delete Person.prototype.name
:
function Person(){ this.name = 'wenzi'; } Person.prototype.name = '蚊子'; var student = new Person(); console.log( student.name ); // wenzi console.log( delete student.name ); // true,删除成功 console.log( student.name ); // 蚊子 console.log( delete student.name ); // true console.log( student.name ); // 蚊子 console.log( delete Person.prototype.name );// true,删除成功 console.log( student.name ); // undefined
위의 예에서 일부 변수 또는 속성은 성공적으로 삭제될 수 있지만 다른 변수 또는 속성은 삭제할 수 없습니다. 따라서 이 변수 또는 속성을 삭제할 수 있는지 여부는 어떻게 결정됩니까?
ECMA-262 5판은 JS 객체 속성(JS 엔진에서 사용되며 외부에서 직접 액세스할 수 없음)의 특성을 정의합니다. ECMAScript에는 데이터 속성과 접근자 속성이라는 두 가지 속성이 있습니다.
데이터 속성은 값을 읽거나 쓸 수 있는 데이터 값이 포함된 위치를 나타냅니다. 이 속성에는 해당 동작을 설명하는 4가지 속성이 있습니다.
객체 속성의 기본 특성(기본값은 true)을 수정하려면 Object.defineProperty() 메서드를 호출하면 됩니다. 이 메서드는 속성이 위치한 객체, 속성 이름 및 설명자 객체( 구성 가능, 번호 매기기 가능, 쓰기 가능 및 값이어야 하며 하나 이상의 값을 설정할 수 있습니다.
은 다음과 같습니다.
var person = {}; Object.defineProperty(person, 'name', { configurable: false, // 不可删除,且不能修改为访问器属性 writable: false, // 不可修改 value: 'wenzi' // name的值为wenzi }); console.log( person.name); // wenzi console.log( delete person.name ); // false,无法删除 person.name = 'lily'; console.log( person.name ); // wenzi
person.name 값을 삭제하거나 재설정하지 않는 것을 볼 수 있습니다. 이는 DefineProperty 함수를 호출하면 객체 속성의 특성이 수정되기 때문입니다. 더 이상 true로 수정하는 데 사용되지 않습니다(실행 시 다음 오류가 보고됩니다: Uncaught TypeError: Cannot redefine property: name);
주로 getter 및 setter 함수 쌍이 포함되어 있습니다. 접근자 속성을 읽을 때 getter가 호출되어 유효한 값을 반환하고, 새 값을 쓰기 위해 setter가 호출됩니다. 속성에는 다음과 같은 4가지 특성이 있습니다.
접근자 속성은 직접 정의할 수 없으며 다음과 같이 DefineProperty()를 사용하여 정의해야 합니다.
var person = { _age: 18 }; Object.defineProperty(person, 'isAdult', { Configurable : false, get: function () { if (this._age >= 18) { return true; } else { return false; } } }); console.log( person.isAdult ); // true
그러나 여전히 주의가 필요한 것이 하나 있습니다. Object.defineProperty() 메서드로 속성을 설정할 때 접근자 속성(set 및 get)과 데이터 속성(writable 또는 value)을 동시에 선언할 수 없습니다. 즉, 속성에 쓰기 가능 또는 값 속성 세트가 있는 경우 이 속성은 get 또는 set을 선언할 수 없으며 그 반대의 경우도 마찬가지입니다.
다음과 같이 정의하면 접근자 속성과 데이터 속성이 동시에 존재하게 됩니다.
var o = {}; Object.defineProperty(o, 'name', { value: 'wenzi', set: function(name) { myName = name; }, get: function() { return myName; } });
上面的代码看起来貌似是没有什么问题,但是真正执行时会报错,报错如下:
Uncaught TypeError: Invalid property. A property cannot both have accessors and be writable or have a value
对于数据属性,可以取得:configurable,enumberable,writable和value;
对于访问器属性,可以取得:configurable,enumberable,get和set。
由此我们可知:一个变量或属性是否可以被删除,是由其内部属性Configurable
进行控制的,若Configurable
为true,则该变量或属性可以被删除,否则不能被删除。
可是我们应该怎么获取这个Configurable
值呢,总不能用delete试试能不能删除吧。有办法滴!!
ES5为我们提供了Object.getOwnPropertyDescriptor(object, property)
来获取内部属性。
如:
var person = {name:'wenzi'}; var desp = Object.getOwnPropertyDescriptor(person, 'name'); // person中的name属性 console.log( desp ); // {value: "wenzi", writable: true, enumerable: true, configurable: true}
通过Object.getOwnPropertyDescriptor(object, property)
我们能够获取到4个内部属性,configurable控制着变量或属性是否可被删除。这个例子中,person.name的configurable是true,则说明是可以被删除的:
console.log( person.name ); // wenzi console.log( delete person.name ); // true,删除成功 console.log( person.name ); // undefined
我们再回到最开始的那个面试题:
a = 1; var desp = Object.getOwnPropertyDescriptor(window, 'a'); console.log( desp.configurable ); // true,可以删除 var b = 2; var desp = Object.getOwnPropertyDescriptor(window, 'b'); console.log( desp.configurable ); // false,不能删除
跟我们使用delete操作删除变量时产生的结果是一样的。
别看一个简简单单的delete操作,里面其实包含了很多的原理!