//通过var声明的变量或function声明的函数是全局对象的不可配置属性
var x = 1;
delete this.x; //返回false
function f() {}
delete this.f; //返回false
六.属性的特性
上面已经说到了属性的可配置性特性,因为下面要说的检测属性和枚举属性还要用到属性的特性这些概念,所以现在就先具体说说属性的特性吧!
除了包含名字和值之外,属性还包含一些标识它们可写、可枚举、可配置的三种特性。在ECMAScript 3中无法设置这些特性,所有通过ECMAScript 3的程序创建的属性都是可写的、可枚举的和可配置的,且无法对这些特性做修改。ECMAScript 5中提供了查询和设置这些属性特性的API。这些API对于库的开发者非常有用,因为:
①可以通过这些API给原型对象添加方法,并将它们设置成不可枚举的,这让它们更像内置方法;
②可以通过这些API给对象定义不能修改或删除的属性,借此“锁定”这个对象;
在这里我们将存取器属性的getter和setter方法看成是属性的特性。按照这个逻辑,我们也可以把属性的值同样看做属性的特性。因此,可以认 为属性包含一个名字和4个特性。数据属性的4个特性分别是它的值(value)、可写性(writable)、可枚举性(enumerable)和可配置 性(configurable)。存取器属性不具有值特性和可写性它们的可写性是由setter方法是否存在与否决定的。因此存取器属性的4个特性是读取 (get)、写入(set)、可枚举性和可配置性。
为了实现属性特性的查询和设置操作,ECMAScript 5中定义了一个名为“属性描述符”(property descriptor)的对象,这个对象代表那4个特性。描述符对象的属性和它们所描述的属性特性是同名的。因此,数据属性的描述符对象的属性有 value、writable、enumerable和configurable。存取器属性的描述符对象则用get属性和set属性代替value和 writable。其中writable、enumerable和configurable都是布尔值,当然,get属性和set属性是函数值。通过调用 Object.getOwnPropertyDescriptor()可以获得某个对象特定属性的属性描述符:
从函数名字就可以看出,Object.getOwnPropertyDescriptor()只能得到自有属性的描述符,对于继承属性和不存在的属性它都返回undefined。要想获得继承属性的特性,需要遍历原型链(不会遍历原型链?不要急,下面会说到的)。
要想设置属性的特性,或者想让新建属性具有某种特性,则需要调用Object.definePeoperty(),传入需要修改的对象、要创建或修改的属性的名称以及属性描述符对象:
可以看到:
①传入Object.defineProperty()的属性描述符对象不必包含所有4个特性;
②可写性控制着对属性值的修改;
③可枚举性控制着属性是否可枚举(枚举属性,下面会说的);
④可配置性控制着对其他特性(包括前面说过的属性是否可以删除)的修改;
如果要同时修改或创建多个属性,则需要使用Object.defineProperties()。第一个参数是要修改的对象,第二个参数是一个映射表,它包含要新建或修改的属性的名称,以及它们的属性描述符,例如:
var p = Object.defineProperties({},{ x: {value: 1, writable: true, enumerable: true, configurable: true}, y: {value: 2, writable: true, enumerable: true, configurable: true}, r: {get: function(){return 88;}, set: function(newvalue){this.x =newvalue;},enumerable: true, configurable: true}, greet: {value: function(){console.log('hello,world');}, writable: true, enumerable: true, configurable: true} });
相信你也已经从实例中看出:Object.defineProperty()和Object.defineProperties()都返回修改后的对象。
前面我们说getter和setter存取器属性时使用对象直接量语法给新对象定义存取器属性,但并不能查询属性的getter和setter方法 或给已有的对象添加新的存取器属性。在ECMAScript 5中,就可以通过Object.getOwnPropertyDescriptor()和Object.defineProperty()来完成这些工作 啦!但在ECMAScript 5之前,大多数浏览器(IE除外啦)已经支持对象直接量语法中的get和set写法了。所以这些浏览器还提供了非标准的老式API用来查询和设置 getter和setter。这些API有4个方法组成,所有对象都拥有这些方法。__lookupGetter__()和 __lookupSetter__()用以返回一个命名属性的getter和setter方法。__defineGetter__()和 __defineSetter__()用以定义getter和setter。这四个方法都是以两条下划线做前缀,两条下划线做后缀,以表明它们是非标准方 法。下面是它们用法:
七.检测属性
JavaScript对象可以看做属性的集合,那么我们有时就需要判断某个属性是否存在于某个对象中,这就是接下来要说的检测属性。
检测一个对象的属性也有三种方法,下面就来详细说说它们的作用及区别!
1.in运算符
in运算符左侧是属性名(字符串),右侧是对象。如果对象的自有属性或继承属性中包含这个属性则返回true,否则返回false。