js中的内部属性与delete操作符
本文正式地址:http://www.xiabingbao.com/javascript/2015/08/03/javascript-delete-configurable
在讲解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;而delete能成功删除变量b,则返回true。
除了上述的两种情况,还有其他的各种常用变量也有能被delete删除的,也有不能被删除的。我们先不管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]
删除function类型的变量:
// chrome 不能删除;火狐可以删除
function func(){
}
console.log( func );
console.log( delete func );
console.log( func );
删除function.length,该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,而不是删除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
删除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删除属性时,删除的仅仅是实例对象本身的属性,而不能删除prototype上的属性,即使再删一次也是删除掉不的;若要删除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 数据属性
数据属性指包含一个数据值的位置,可在该位置读取或写入值,该属性有4个供述其行为的特性:
. [[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,写入新值;该属性有以下4个特征:
. [[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操作,里面其实包含了很多的原理!
本文正式地址:http://www.xiabingbao.com/javascript/2015/08/03/javascript-delete-configurable
js中的内部属性与delete操作符的更多相关文章
- js中获取css属性
直接获取 window.onload = function() { var but = document.getElementById('button'); var div = document.ge ...
- JS中获取元素属性的逆天大法
给大家聊下js中获取元素属性的逆天大法,胆小慎入,切记切记!!! innerHTML.outerHTML.innerText .outerText.value.text().html(),val() ...
- 【学习笔记】六:面向对象的程序设计——理解JS中的对象属性、创建对象、JS中的继承
ES中没有类的概念,这也使其对象和其他语言中的对象有所不同,ES中定义对象为:“无序属性的集合,其属性包含基本值.对象或者函数”.现在常用的创建单个对象的方法为对象字面量形式.在常见多个对象时,使用工 ...
- JS中的prototype属性
JavaScript是基于对象的,任何元素都可以看成对象.然而,类型和对象是不同的.本文中,我们除了讨论类型和对象的一些特点之外,更重要的 是研究 如何写出好的并且利于重用的类型.毕竟,JavaSc ...
- 关于在JS中设置标签属性
Attribute 该属性主要是用来在标签行内样式,添加.删除.获取属性.且适用于自定义属性. setAttribute("属性名",属性值“”):这个是用来设置标签属性的: re ...
- 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( ...
- JS中对象按属性排序(冒泡排序)
在实际工作经常会出现这样一个问题:后台返回一个数组中有i个json数据,需要我们根据json中某一项进行数组的排序. 例如返回的数据结构大概是这样: { result:[ {id:,name:'中国银 ...
- js中的位置属性
原生js中位置信息 clientLeft,clientTop:表示内容区域的左上角相对于整个元素左上角的位置(包括边框),实测,clientLeft=左侧边框的宽度,clientTop=顶部边框的宽度 ...
- Angular JS中自定义标签 属性绑定的解释
看到自定义标签的文档时,文档作者解释的能力实在太弱,也可能是本人太笨,一下绕不过来. 看了一个stackoverflow答案,才算明白,在此贴出翻译,以供大家参考. .csharpcode, .csh ...
随机推荐
- C语言中的extern
extern: 这个关键字真的比较恶心,在定义变量的时候,extern居然可以被省略(定义时,默认均省略): 在声明变量的时候,extern必须加在变量前. 所以有时候你搞不清楚是声明还是定义.:变量 ...
- 我与前端之间不得不说的三天两夜之jQuery
前端基础之jquery 一 jQuery是什么? [1] jQuery由美国人John Resig创建,至今已吸引了来自世界各地的众多 javascript高手加入其team. [2] jQuery是 ...
- VirtualBox AndroidX86 网络设置
在Virtualbox中,把虚拟机网络设为“网络地址转换(NAT)”模式,高级中控制芯片(T)选择:PCnet-FAST III(Am79C973), 然后启动你的android-x86 4.0虚拟机 ...
- Mac使用操作
快捷键退出程序:Command + Q 快捷键关闭窗口:Command + W(关闭程序的窗口不一定是退出程序) 单击左上角黑苹果,菜单里面有强制退出 Finder菜单的偏好设置,高级设置菜单里面可以 ...
- 一步一步学EF系列一【最简单的一个实例】
整个文章我都会用最简单,最容易让人理解的方式给大家分享和共同学习.(由于live Writer不靠谱 又得补发一篇) 一.安装 Install-Package EntityFramework 二.简单 ...
- 基于HTML5 FileSystem API的使用介绍(转)
FileSystem提供了文件夹和文件的创建.移动.删除等操作,大大方便了数据的本地处理, 而且所有的数据都是在沙盒(sandboxed)中,不同的web程序不能互相访问,这就保证了数据 的完整和安全 ...
- hdu4057 Rescue the Rabbit
地址:http://acm.hdu.edu.cn/showproblem.php?pid=4057 题目: Rescue the Rabbit Time Limit: 20000/10000 MS ( ...
- HDU - 5406 CRB and Apple (费用流)
题意:对于给定的物品,求两个在高度上单调不递增,权值上单调不递减的序列,使二者长度之和最大. 分析:可以用费用流求解,因为要求长度和最大,视作从源点出发的流量为2的费用流,建负权边,每个物品只能取一次 ...
- HDU - 4725 The Shortest Path in Nya Graph(拆点+Dijkstra)
题意:N个点,每个点有一个层号L,相邻的两层 Li 与 Li+1 之间的距离为C.另外给出M条无向边,求从点1到点N的最短路. 分析:同一层之间的两点距离并不是0,这是一个小坑.依次把相邻两层的所有点 ...
- NodeJS中间层搭建
前言 最近碰了个壁,公司开发的一个新项目里我大胆地提出要前后端完全分离,用JavaScript模板引擎.ajax.路由等技术替代繁琐的前后端混合的业务逻辑,项目进行到一半前辈提出来仅仅靠前端的力量无法 ...