深入理解JavaScript中的delete操作符与内部属性Configurable

作者:拾光

时间:2026-10-29

浏览:617

本文深入解析JavaScript中delete操作符的工作原理,重点阐述ECMAScript定义的内部属性Configurable如何控制属性的可删除性。通过对比数据属性与访问器属性的特征,结合Object.defineProperty和Object.getOwnPropertyDescriptor的使用示例,说明为何部分变量无法被删除,并展示如何正确获取和修改属性内部特征。

文章目录

在深入探讨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命令可以成功删除该变量,再次访问时返回undefined;而若使用var声明变量,则delete命令无法将其删除,再次访问时仍能获取到原始值2。

1. delete操作符

执行delete删除变量或对象属性时,若删除成功则返回true,否则返回false。例如前文示例中,delete尝试删除变量a失败返回false,而成功删除变量b则返回true。

除了上述基本变量,其他常见类型的变量在delete操作下的表现各异,有的可被删除,有的则不能。此处暂不深究其背后的原理,仅关注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 );

尝试删除函数的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,删除成功

尝试删除prototype属性本身,而非其上的具体属性:


function Person(){
}
Person.prototype.name = "蚊子";
console.log( delete Person.prototype );	// false,无法删除
console.log( delete Object.prototype );	// false

尝试删除数组和字符串的length属性:


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

尝试删除普通对象中的属性:


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仅能删除实例对象自身的属性,无法删除prototype链上的属性,即使多次执行delete也无济于事。若要删除prototype上的属性或方法,必须采用如下方式: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

2. js的内部属性

在前述示例中,部分变量或属性可被成功删除,而另一部分则不能。决定这一差异的关键因素是什么?

ECMA-262第5版定义了JS对象属性的特征(供JS引擎内部使用,外部不可直接访问)。ECMAScript将属性分为两类:数据属性和访问器属性。

2.1 数据属性

数据属性包含一个存储数据值的位置,可在此读取或写入值。该属性具备四个描述其行为特性的特征:

  • [[configurable]]:表示能否使用delete操作符删除该属性从而重新定义,或能否将其修改为访问器属性。默认值为true;
  • [[Enumberable]]:表示是否可通过for-in循环返回该属性。默认值为true;
  • [[Writable]]:表示是否可修改属性的值。默认值为true;
  • [[Value]]:包含该属性的实际数据值。读取或写入操作均针对此值。默认值为undefined;例如前文实例对象Person中定义的name属性,其值为'wenzi',对该值的修改均反映在此位置。

若要修改对象属性的默认特征(默认均为true),可调用Object.defineProperty()方法。该方法接收三个参数:属性所在的对象、属性名以及一个描述符对象(必须包含configurable、enumberable、writable和value中的一个或多个)。

示例如下:


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

可以看出,此时delete及重置person.name的值均失效,原因在于调用defineProperty函数修改了对象属性的特征。值得注意的是,一旦将configurable设置为false,便无法再使用defineProperty将其改回true(执行时会报错:Uncaught TypeError: Cannot redefine property: name);

2.2 访问器属性

访问器属性主要包含一对getter和setter函数。读取访问器属性时,会调用getter返回有效值;写入访问器属性时,则调用setter写入新值。该属性具备以下四个特征:

  • [[Configurable]]:是否可通过delete操作符删除并重新定义属性;
  • [[Numberable]]:是否可通过for-in循环查找该属性;
  • [[Get]]:读取属性时自动调用,默认值为undefined;
  • [[Set]]:写入属性时自动调用,默认值为undefined;

访问器属性无法直接定义,必须使用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)。即若某属性已设置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尝试删除来测试吧。其实是有办法的!!

2.3 获取内部属性

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操作删除变量时产生的结果完全一致。

3. 总结

看似简单的delete操作,背后实则蕴含了丰富的原理!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章