本文正式地址:http://www.xiabingbao.com/javascript/2015/08/03/javascript-delete-configurable

在讲解Configurable之前,我们首先来看一道面试题:

  1. a = 1;
  2. console.log( window.a ); // 1
  3. console.log( delete window.a ); // true
  4. console.log( window.a ); // undefined
  5. var b = 2;
  6. console.log( window.b ); // 2
  7. console.log( delete window.b ); // false
  8. console.log( window.b ); // 2

从上面的这道题可以看出两个的区别:在没有使用var声明变量时,使用delete关键词是可以进行删除的,再次获取时值就是undefined了;在使用var声明的变量,使用delete是不能删除的,再获取时值依然是2。

1. delete操作符

使用delete删除变量或属性时,删除成功返回true,否则返回false。如上面的例子中,delete无法删除变量a时,则返回false;而delete能成功删除变量b,则返回true。

除了上述的两种情况,还有其他的各种常用变量也有能被delete删除的,也有不能被删除的。我们先不管delete这些变量时,为什么会产生这样的结果,这里只看他的返回值:

删除delete数组中其中的一个元素:

  1. // 使用for~in是循环不到的,直接忽略到该元素
  2. // 使用for()可以得到该元素,但是值是undefined
  3. var arr = [1, 2, 3, 4];
  4. console.log( arr ); // [1, 2, 3, 4]
  5. console.log( delete arr[2] ); // true,删除成功
  6. console.log( arr ); // [1, 2, undefined, 4]

删除function类型的变量:

  1. // chrome 不能删除;火狐可以删除
  2. function func(){
  3. }
  4. console.log( func );
  5. console.log( delete func );
  6. console.log( func );

删除function.length,该length是获取形参的个数:

  1. function func1(a, b){
  2. }
  3. console.log( func1.length ); // 2
  4. console.log( delete func1.length ); // true,删除成功
  5. console.log( func1.length ); // 0

删除常用变量:

  1. console.log( delete NaN ); // false,删除失败
  2. console.log( delete undefined );// false
  3. console.log( delete Infinity ); // false
  4. console.log( delete null ); // true,删除成功

删除prototype,而不是删除prototype上的属性:

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

删除数组和字符串的length时:

  1. var arr = [1, 2, 3, 4];
  2. console.log( arr.length ); // 4
  3. console.log( delete arr.length ); // false,删除失败
  4. console.log( arr.length ); // 4
  5. var str = 'abcdefg';
  6. console.log( str.length ); // 7
  7. console.log( delete str.length ); // false,删除失败
  8. console.log( str.length ); // 7

删除obj中的属性时:

  1. var obj = {name:'wenzi', age:25};
  2. console.log( obj.name ); // wenzi
  3. console.log( delete obj.name ); // true,删除成功
  4. console.log( obj.name ); // undefined
  5. console.log( obj ); // { age:25 }

删除实例对象中的属性时,从以下的输出结果可以看出,使用delete删除属性时,删除的仅仅是实例对象本身的属性,而不能删除prototype上的属性,即使再删一次也是删除掉不的;若要删除prototype上的属性的属性或方法,只能是:delete Person.prototype.name

  1. function Person(){
  2. this.name = 'wenzi';
  3. }
  4. Person.prototype.name = '蚊子';
  5. var student = new Person();
  6. console.log( student.name ); // wenzi
  7. console.log( delete student.name ); // true,删除成功
  8. console.log( student.name ); // 蚊子
  9. console.log( delete student.name ); // true
  10. console.log( student.name ); // 蚊子
  11. console.log( delete Person.prototype.name );// true,删除成功
  12. console.log( student.name ); // undefined

2. js的内部属性

在上面的例子中,有的变量或属性能够删除成功,而有的变量或属性则无法进行删除,那是什么决定这个变量或属性能不能被删除呢。

ECMA-262第5版定义了JS对象属性中特征(用于JS引擎,外部无法直接访问)。ECMAScript中有两种属性:数据属性和访问器属性。

2.1 数据属性

数据属性指包含一个数据值的位置,可在该位置读取或写入值,该属性有4个供述其行为的特性:

. [[configurable]]:表示能否使用delete操作符删除从而重新定义,或能否修改为访问器属性。默认为true;

. [[Enumberable]]:表示是否可通过for-in循环返回属性。默认true;

. [[Writable]]:表示是否可修改属性的值。默认true;

. [[Value]]:包含该属性的数据值。读取/写入都是该值。默认为undefined;如上面实例对象Person中定义了name属性,其值为’wenzi’,对该值的修改都反正在这个位置

要修改对象属性的默认特征(默认都为true),可调用Object.defineProperty()方法,它接收三个参数:属性所在对象,属性名和一个描述符对象(必须是:configurable、enumberable、writable和value,可设置一个或多个值)。

如下:

  1. var person = {};
  2. Object.defineProperty(person, 'name', {
  3. configurable: false, // 不可删除,且不能修改为访问器属性
  4. writable: false, // 不可修改
  5. value: 'wenzi' // name的值为wenzi
  6. });
  7. console.log( person.name); // wenzi
  8. console.log( delete person.name ); // false,无法删除
  9. person.name = 'lily';
  10. 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,写入新值;该属性有以下4个特征:

. [[Configurable]]:是否可通过delete操作符删除重新定义属性;

. [[Numberable]]:是否可通过for-in循环查找该属性;

. [[Get]]:读取属性时自动调用,默认:undefined;

. [[Set]]:写入属性时自动调用,默认:undefined;

访问器属性不能直接定义,必须使用defineProperty()来定义,如下:

  1. var person = {
  2. _age: 18
  3. };
  4. Object.defineProperty(person, 'isAdult', {
  5. Configurable : false,
  6. get: function () {
  7. if (this._age >= 18) {
  8. return true;
  9. } else {
  10. return false;
  11. }
  12. }
  13. });
  14. console.log( person.isAdult ); // true

不过还是有一点需要额外注意一下,Object.defineProperty()方法设置属性时,不能同时声明访问器属性(set和get)和数据属性(writable或者value)。意思就是,某个属性设置了writable或者value属性,那么这个属性就不能声明get和set了,反之亦然。

如若像下面的方式进行定义,访问器属性和数据属性同时存在:

  1. var o = {};
  2. Object.defineProperty(o, 'name', {
  3. value: 'wenzi',
  4. set: function(name) {
  5. myName = name;
  6. },
  7. get: function() {
  8. return myName;
  9. }
  10. });

上面的代码看起来貌似是没有什么问题,但是真正执行时会报错,报错如下:

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)来获取内部属性。

如:

  1. var person = {name:'wenzi'};
  2. var desp = Object.getOwnPropertyDescriptor(person, 'name'); // person中的name属性
  3. console.log( desp ); // {value: "wenzi", writable: true, enumerable: true, configurable: true}

通过Object.getOwnPropertyDescriptor(object, property)我们能够获取到4个内部属性,configurable控制着变量或属性是否可被删除。这个例子中,person.name的configurable是true,则说明是可以被删除的:

  1. console.log( person.name ); // wenzi
  2. console.log( delete person.name ); // true,删除成功
  3. console.log( person.name ); // undefined

我们再回到最开始的那个面试题:

  1. a = 1;
  2. var desp = Object.getOwnPropertyDescriptor(window, 'a');
  3. console.log( desp.configurable ); // true,可以删除
  4. var b = 2;
  5. var desp = Object.getOwnPropertyDescriptor(window, 'b');
  6. console.log( desp.configurable ); // false,不能删除

跟我们使用delete操作删除变量时产生的结果是一样的。

3. 总结

别看一个简简单单的delete操作,里面其实包含了很多的原理!

本文正式地址:http://www.xiabingbao.com/javascript/2015/08/03/javascript-delete-configurable

js中的内部属性与delete操作符的更多相关文章

  1. js中获取css属性

    直接获取 window.onload = function() { var but = document.getElementById('button'); var div = document.ge ...

  2. JS中获取元素属性的逆天大法

    给大家聊下js中获取元素属性的逆天大法,胆小慎入,切记切记!!! innerHTML.outerHTML.innerText .outerText.value.text().html(),val() ...

  3. 【学习笔记】六:面向对象的程序设计——理解JS中的对象属性、创建对象、JS中的继承

    ES中没有类的概念,这也使其对象和其他语言中的对象有所不同,ES中定义对象为:“无序属性的集合,其属性包含基本值.对象或者函数”.现在常用的创建单个对象的方法为对象字面量形式.在常见多个对象时,使用工 ...

  4. JS中的prototype属性

    JavaScript是基于对象的,任何元素都可以看成对象.然而,类型和对象是不同的.本文中,我们除了讨论类型和对象的一些特点之外,更重要的 是研究  如何写出好的并且利于重用的类型.毕竟,JavaSc ...

  5. 关于在JS中设置标签属性

    Attribute 该属性主要是用来在标签行内样式,添加.删除.获取属性.且适用于自定义属性. setAttribute("属性名",属性值“”):这个是用来设置标签属性的: re ...

  6. js中数组删除 splice和delete的区别,以及delete的使用

    var test=[];test[1]={name:'1',age:1};test[2]={name:'2',age:2};test[4]={name:'3',age:3}; console.log( ...

  7. JS中对象按属性排序(冒泡排序)

    在实际工作经常会出现这样一个问题:后台返回一个数组中有i个json数据,需要我们根据json中某一项进行数组的排序. 例如返回的数据结构大概是这样: { result:[ {id:,name:'中国银 ...

  8. js中的位置属性

    原生js中位置信息 clientLeft,clientTop:表示内容区域的左上角相对于整个元素左上角的位置(包括边框),实测,clientLeft=左侧边框的宽度,clientTop=顶部边框的宽度 ...

  9. Angular JS中自定义标签 属性绑定的解释

    看到自定义标签的文档时,文档作者解释的能力实在太弱,也可能是本人太笨,一下绕不过来. 看了一个stackoverflow答案,才算明白,在此贴出翻译,以供大家参考. .csharpcode, .csh ...

随机推荐

  1. (1.3.1)连接安全(连接实例与网络协议及TDS端点)

    连接安全是sql server安全配置的第1道防线,它保证只有许可的客户端能够连接sql server,而且可以限制连接可用的通道(各种网络协议). 1.连接到sql server实例 sql ser ...

  2. Linux kill和kill-9区别

    进程状态转换图 kill和kill -9,两个命令在linux中都有杀死进程的效果,然而两命令的执行过程却大有不同,在程序中如果用错了,可能会造成莫名其妙的现象. 执行kill命令,系统会发送一个SI ...

  3. Selenium 方法封装 一

    Selenium 封装 Selenium 封装 WebDriver对页面的操作,需要找到一个WebElement,然后再对其进行操作,比较繁琐: WebElement element =driver. ...

  4. [笔记]mosh使用笔记

    听说mosh好使,那么怎么在Mac本下使用mosh来登录Ubuntu及AWS服务器呢? mosh介绍 mosh官网在:https://mosh.org/ 代码开源在:https://github.co ...

  5. fake-useragent,python爬虫伪装请求头

    在编写爬虫进行网页数据的时候,大多数情况下,需要在请求是增加请求头,下面介绍一个python下非常好用的伪装请求头的库:fake-useragent,具体使用说明如下: 1.在scrapy中的使用 第 ...

  6. Git在Githib和Github上的使用

    本文使用的环境是linux里 一.git的常用命令解释: 1.基础命令: git init #创建版本库 git add <file> #将文件修改添加到暂存区 git commit -m ...

  7. 264. Ugly Number II(丑数 剑指offer 34)

    Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors ...

  8. BitmapFactory.decodeStream(inputStream)返回null的解决方法

    场景:Android,通过inputStream从网络上获取图片 随后两次使用BitmapFactory对InputStream进行操作,一次获取宽高,另一次缩放 但是在缩放时,发现inputStre ...

  9. spark[源码]-任务调度源码分析[三]

    前言 在上一篇文章中,我主要是讲解了DAG阶段的处理,spark是如何将一个job根据宽窄依赖划分出多个stage的,在最后一步中是将生成的TaskSet提交给了TaskSchedulerInmpl的 ...

  10. Eclipse 导入Maven 项目报错

    新建Maven项目时出错:org.apache.maven.archiver.MavenArchiver.getManifest   新建Maven项目时出错:org.apache.maven.arc ...