我们先创建一个对象:

var person = {
  name: "Nicholas",
  _job: "Software Engineer",
  sayName: function(){
    alert(this.name);
  },
  get job(){
return this._job;
},
  set job(newJob){
this._job=newJob;
}
}

  在这个对象中,我们定义了一个name属性和一个_job属性;至于以set和get开头的两处代码,他们共同定义了一个属性job。明显属性job和_job、name的是不同的。是的,JavaScript中的对象有两种不同类型的属性:数据属性和访问器属性。

  name和_job是数据属性,job是访问器。数据属性和访问器属性的最大的不同就在于:当访问一个访问器属性时,得到get后面函数的返回值;给一个访问器属性赋值时,执行的是set后面的函数,这个函数以赋的值为参数:

console.info(person.job);//Software Engineer
person.job="Coder";
console.info(person.job);//Coder
console.info(person._job);//Coder

  在set函数中我们通过this改变了_job的值(this指向person这个对象);

  在了解了对象属性的类型后,我们再来看看对象属性特性。每个对象的属性在创建时都带有一些特征值,JavaScript通过这些特征值来定义它们的行为。

我们在创建person对象时没有为它的属性们直接指定特征值,JavaScript自动为它们创建了属性特性。在ES3中属性特性不可访问,但是ES5中属性的特性可以通过Object.getOwnPropertyDescriptorsObject.getOwnPropertyDescriptor得到:

var descriptors= Object.getOwnPropertyDescriptors(person)
//descriptors的内容如下;
{
age:{value: 29, writable: true, enumerable: true, configurable: true}
job:{enumerable: true, configurable: true, get: ƒ, set: ƒ}
name:{value: "Nicholas", writable: true, enumerable: true, configurable: true}
sayName:{writable: true, enumerable: true, configurable: true, value: ƒ}
_job:{value: "Coder", writable: true, enumerable: true, configurable: true}
}

  Object.getOwnPropertyDescriptors返回一个对象,包含了描述person对象的所有属性的特性。其中每一个属性的特性用一个对象表示,我们叫它属性描述符。我们可以看到:数据属性的描述符有四个属性:value,writable ,enumerable ,configurable ;访问器属性的描述符也有四个属性:enumerable ,configurable,get,set ;

那么我们分别看下数据属性及访问器属性的这几个描述符:

数据属性

  数据属性的描述符的有四个属性分别是:

  1.value:包含这个属性的数据值。读取属性的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。默认为undefined.

  2.writable:表示能否修改属性的值。是一个bool值,默认为true

  3.enumerable:属性是否可枚举,即能否通过for-in循环返回属性。是一个bool值,默认为true

  4.configrable:属性是否可配置。即属性能否通过delete删除,能否修改属性的特性,或者能否把属性修改为访问器属性。是一个bool值,默认为true

  我们最初开始创建的person对象的属性name,它的value为“Nicholas”,其他描述符为true。

请看例子:

访问器属性 

  访问器属性的描述符的有四个属性分别是:

  1.get:在读取属性时调用的函数。默认值为 undefined。

  2.set:在写入属性时调用的函数。默认值为 undefined。

  3.enumerable:属性是否可枚举,即能否通过for-in循环返回属性。是一个bool值,默认为true

  4.configrable:属性是否可配置。即属性能否通过delete删除,能否修改属性的特性,或者能否把属性修改为数据属性。是一个bool值,默认为true

  我们最初开始创建的person对象的属性job,它的get和set值分别是我们指定的函数,其他描述符为true。

  要修改属性默认的特性,必须使用 ECMAScript 5 的 Object.defineProperty或 Object.defineProperties

  有了定义属性特性的方法,那我们通过代码来探索下这些属性特性的作用:

  数据属性:

var person ={};
//除了configrable之外,其他三个属性相互之间不会影响,读者可以自己测试 console.info('---------------------writable start--------------------------------');
Object.defineProperty(person, "name", {
writable: false,
enumerable:true,
configurable:true,
value: "Nicholas"
});
console.info(person.name); //"Nicholas"
person.name = "Greg";
//writable为false,属性不可修改
console.info(person.name); //"Nicholas" //writable为false,但configrable为true,我们可以重新配置属性描述符,
Object.defineProperty(person, "name", {
writable: false,
enumerable:true,
configurable:true,
value: "John"
});
console.info(person.name)//John delete person.name
//但configrable为true,属性可以被删除
console.info (person.name)//undefined console.info('---------------------writable end--------------------------------'); console.info('---------------------enumerable start--------------------------------');
var person={};
Object.defineProperty(person, "name", {
writable: false,
enumerable:true,
configurable:true,
value: "Nicholas"
}); //enumerable为true属性可枚举
for(var prop in person){
console.info(prop)//name
} Object.defineProperty(person, "name", {
writable: false,
enumerable:false,
configurable:true,
value: "Nicholas"
}); //enumerable为false属性不可枚举,循环体不执行
for(var prop in person){
console.info(prop)//
} console.info('---------------------enumerable end--------------------------------');
console.info('---------------------configurable start--------------------------------'); var person={};
Object.defineProperty(person, "name", {
writable: true,
enumerable:true,
configurable:false,
value: "Nicholas"
});
//configurable为false,writable为true,属性仍然可修改
person.name="John"
console.info(person.name);//John //configurable为false,writable为true,仍然可以通过配置的方式改变属性值
Object.defineProperty(person, "name", {
writable: true,
enumerable:true,
configurable:false,
value: "Nicholas"
}); console.info(person.name) //configurable为false,enumerable为ture,属性可枚举
for(var prop in person){
console.info(prop)//name
} //configurable为false,我们仍然可以把writable属性由true改为false
Object.defineProperty(person, "name", {
writable: false,
enumerable:true,
configurable:false,
value: "Nicholas"
});
console.info(Object.getOwnPropertyDescriptor(person,"name"))//{value: "Nicholas", writable: false, enumerable: true, configurable: false} //configurable为false,writable为false,不能通过配置改变value的值
try{
Object.defineProperty(person, "name", {
writable: false,
enumerable:true,
configurable:false,
value: "John"
});
}catch(error){
console.info("value change error");
console.info(Object.getOwnPropertyDescriptor(person,"name"))//{value: "Nicholas", writable: false, enumerable: true, configurable: false}
} //configurable为false,但是不能把writable属性由false改为true
try{
Object.defineProperty(person, "name", {
writable: true,
enumerable:true,
configurable:false,
value: "Nicholas"
});
}catch(error){
console.info("writable false to true error")
console.info(Object.getOwnPropertyDescriptor(person,"name"))//{value: "Nicholas", writable: false, enumerable: true, configurable: false}
} //configurable为false,不能改变enumerable的值
try{
Object.defineProperty(person, "name", {
writable: false,
enumerable:false,
configurable:false,
value: "Nicholas"
});
}catch(error){
console.info("enumerable change error");
console.info(Object.getOwnPropertyDescriptor(person,"name"))//{value: "Nicholas", writable: false, enumerable: true, configurable: false}
} var person={};
Object.defineProperty(person, "name", {
writable: true,
enumerable:true,
configurable:true,
value: "Nicholas"
}); //configurable为true,可以把数据属性修改为访问器属性
try{
Object.defineProperty(person, "name", {
get: function(){return "Nicholas"},
enumerable:true,
configurable:false
});
}catch(error){
console.info("get error");
}
console.info(Object.getOwnPropertyDescriptor(person,"name"))//{set: undefined, enumerable: true, configurable: false, get: ƒ} var person={};
Object.defineProperty(person, "name", {
writable: true,
enumerable:true,
configurable:false,
value: "Nicholas"
});
//configurable为false,不可以把数据属性修改为访问器属性
try{
Object.defineProperty(person, "name", {
get: function(){return "Nicholas"},
enumerable:true,
configurable:false
});
}catch(error){
console.info("get error");
}
console.info(Object.getOwnPropertyDescriptor(person,"name"))//{value: "Nicholas", writable: true, enumerable: true, configurable: false} console.info('---------------------configurable end--------------------------------');

访问器属性

//访问器属性

console.info("------------------------------------------------------");
var person ={_name:"Nicholas"};
Object.defineProperty(person, "name", {
get: function(){
console.info("get 被调用")
return this._name
},
set:function(newName){
console.info("set 被调用")
this._name=newName
},
enumerable:true,
configurable:true,
});
person.name;//get 被调用
person.name="John";//set 被调用 console.info("------------------------------------------------------");
console.info("----------------------不设set 开始--------------------------------"); var person ={_name:"Nicholas"}; Object.defineProperty(person, "name", {
get: function(){
console.info("get 被调用")
return this._name
},
enumerable:true,
configurable:true,
});
person.name;//get 被调用
person.name="John";//没有设置set,什么也没发生
console.info(person.name)//Nicholas, console.info("----------------------不设set 结束--------------------------------"); console.info("----------------------不设get 开始--------------------------------"); var person ={_name:"Nicholas"}; Object.defineProperty(person, "name", {
set:function(newName){
console.info("set 被调用")
this._name=newName
},
enumerable:true,
configurable:true,
});
console.info(person.name);//没有get,得到 undefined
console.info(person._name);//Nicholas
person.name="John";//set 被调用
console.info(person._name)//John,通过set,_name的值被改变 console.info("----------------------不设get 结束--------------------------------"); console.info("----------------------不设get set开始--------------------------------");
//虽然不报错,但是这个属性没有任何意义
var person ={_name:"Nicholas"};
Object.defineProperty(person, "name", {
enumerable:true,
configurable:true,
});
console.info("----------------------不设get 结束--------------------------------"); console.info("----------------------enumerable 开始--------------------------------");
var person ={_name:"Nicholas"};
Object.defineProperty(person, "name", {
get: function(){
console.info("get 被调用")
return this._name
},
set:function(newName){
console.info("set 被调用")
this._name=newName
},
enumerable:true,
configurable:true,
});
for(var prop in person){
console.info(prop)//_name,name
} Object.defineProperty(person, "name", {
get: function(){
console.info("get 被调用")
return this._name
},
set:function(newName){
console.info("set 被调用")
this._name=newName
},
enumerable:false,
configurable:true,
});
for(var prop in person){
console.info(prop)//_name
}
console.info("----------------------enumerable 结束--------------------------------"); console.info("----------------------configurable 开始--------------------------------");
var person ={_name:"Nicholas"};
Object.defineProperty(person, "name", {
get: function(){
console.info("get 被调用")
return this._name
},
set:function(newName){
console.info("set 被调用")
this._name=newName
},
enumerable:true,
configurable:false,
}); person.name;//get 被调用
person.name="John";//set 被调用
console.info(person.name);//John //报错
try{
Object.defineProperty(person, "name", {
get: function(){
console.info("get 被调用")
return this._name
},
set:function(newName){
console.info("set 被调用")
this._name=newName
},
enumerable:true,
configurable:false,
});
}catch(e){
console.info("不能重新定义name的属性标识符")
} //报错
try{
Object.defineProperty(person, "name", {
value:"123",
writable:true,
enumerable:true,
configurable:false,
});
}catch(e){
console.info("不能重新定义name的属性标识符")
} console.info("----------------------configurable 结束--------------------------------");

 总结一下:

  1.writable为true,属性值就可以修改,无论是通过.运算符还是通过Object.defineProperty方法;

  2.writable为false,不能通过.运算符修改属性。但是在configurable为true的情况下可以通过通过Object.defineProperty方法重新设置value值,从而修改属性值;

  3.只要enumerable为true,属性就可枚举,为false则不可枚举;

  4.configurable为true的情况下,可以对属性描述符对象进行任何修改;

  5.configurable为fasle的情况下,可以通过Object.defineProperty把writable改为true,在writabe为true的情况下,可以修改value的值。

  6.configurable为false的情况下,除第5条的所述的情况外,不能通过Object.defineProperty修改属性的任何特性值。

可扩展性

  ES5定义了三个方法Object.preventExtensionsObject.sealObject.freeze分别定义了不同级别的可扩展性。可点击连接前往MDN阅读;

最后:get、set 与继承

function Person(){}

var p=Person.prototype;
p._name="John";
Object.defineProperty(p,"name",{
get: function(){return this._name},
set: function(newName){ this._name=newName},
enumerable:true,
configurable:true
}) var person=new Person();
console.info(person.name)//John
console.info(person.hasOwnProperty("_name"))//false //虽然name属性的set get方法是定义在原型中的
//但是通过person调用时,它们的this属性会指向person
//所以通过person.name设置属性时,执行set方法中的this._name=newName时,
//会给person对象添加_name属性,并把newName赋给person新建的属性_name;
person.name="Nicholas";
console.info(person.name);//Nicholas
console.info(p._name)//John
console.info(person.hasOwnProperty("name"))//false
console.info(person.hasOwnProperty("_name"))//true

写的有点冗长,但是算是基本测试了各种情况,方便查阅;

  

JavaScript中的对象描述符(属性特性)的更多相关文章

  1. JavaScript中的对象与原型—你不知道的JavaScript上卷读书笔记(四)

    一.对象 对象可以通过两种形式定义:声明(文字)形式和构造形式.即: var myObj = { key: value // ... }; 或: var myObj = new Object(); m ...

  2. js对象—类型和属性特性

    前言 权威指南中摘要的,工作中用不到的,重要的js基础. 三类对象两类属性 内置对象(native object) 是由ECMScript规范定义的对象或者类.例如:函数,数组,日期,正则... 宿主 ...

  3. javascript中的对象,原型,原型链和面向对象

    一.javascript中的属性.方法 1.首先,关于javascript中的函数/“方法”,说明两点: 1)如果访问的对象属性是一个函数,有些开发者容易认为该函数属于这个对象,因此把“属性访问”叫做 ...

  4. (转)javascript中event对象详解

    原文:http://jiajiale.iteye.com/blog/195906 javascript中event对象详解          博客分类: javaScript JavaScriptCS ...

  5. Linux中的文件描述符与打开文件之间的关系

    Linux中的文件描述符与打开文件之间的关系 导读 内核(kernel)利用文件描述符(file descriptor)来访问文件.文件描述符是非负整数.打开现存文件或新建文件时,内核会返回一个文件描 ...

  6. Linux中的文件描述符与打开文件之间的关系------------每天进步一点点系列

    http://blog.csdn.net/cywosp/article/details/38965239 1. 概述     在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件.目录文件. ...

  7. (转)Linux中的文件描述符

    本文转自:http://blog.csdn.net/cywosp/article/details/38965239 作者:cywosp 1. 概述 在Linux系统中一切皆可以看成是文件,文件又可分为 ...

  8. javascript中的对象字面量为啥这么酷

    原文链接 : Why object literals in JavaScript are cool 原文作者 : Dmitri Pavlutin 译者 : neal1991 个人主页:http://n ...

  9. (转)Linux中的文件描述符与打开文件之间的关系

    转:http://blog.csdn.net/cywosp/article/details/38965239 1. 概述     在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件.目录文 ...

随机推荐

  1. SELECT中常用的子查询操作

    MySQL中的子查询 是在MySQL中经常使用到的一个操作,不仅仅是用在DQL语句中,在DDL语句.DML语句中也都会常用到子查询. 子查询的定义: 子查询是将一个查询语句嵌套在另一个查询语句中: 在 ...

  2. Bypass ngx_lua_waf SQL注入防御(多姿势)

    0x00 前言 ​ ngx_lua_waf是一款基于ngx_lua的web应用防火墙,使用简单,高性能.轻量级.默认防御规则在wafconf目录中,摘录几条核心的SQL注入防御规则: select.+ ...

  3. DDMS调试信息

    1.可以使用System.out.println() 2.android.util包下的Log类 该类可以将信息以日志的形式输出到LogCat中: import android.util.Log; S ...

  4. weblogic12C出现“java.lang.ArrayIndexOutOfBoundsException: 48188”

    最近将10G的一个项目转移到12C出现数组越界的问题: 解决办法:  jaxen-1.1.1.jarxom-1.0.jaricu4j-2.6.1.jar  把项目中这三个jar包删除后就可以正常部署了 ...

  5. Ubuntu输入法切换问题

    不知道改了个什么东西,Ubuntu 15.04 中Ctrl+Space不能切换输入法了,因此不能输入英文,shell就更是没法工作,在设置里面找了好久,“文本输入”/“语言支持”/“键盘”里面都没找到 ...

  6. 如何让移植的嵌入式ARM显示中文汉字

    如果你急于在ARM开发板上看到Qt显示中文,而不介意稍次的效果,可以在运行Qt程序时,增加设置字体的参数,比如运行名为hello的Qt程序:./hello -fn unifont 1.首先,需要文泉驿 ...

  7. windos或linux中 which命令 查看当前要执行的命令所在的路径

    whereis 用来查看一个命令或者文件所在的绝对路径,而 which 用来查看当前要执行的命令所在的路径. 下面举个例子来说明.加入你的linux系统上装了多个版本的java.如果你直接在命令行敲命 ...

  8. secureCRT使用退格键(backspace)出现^H解决办法

    解决办法步骤如下: 选项--->会话选项---> 把下面两个打个钩就行了. 原文地址:http://skykiss.blog.51cto.com/blog/2892603/769771 另 ...

  9. 【cs229-Lecture13】高斯混合模型

    本节内容: 1.混合高斯模型: 2.将混合高斯模型应用到混合贝叶斯模型:(应用:文本聚类) 3.结合EM算法,讨论因子分析算法: 4.高斯分布的有用性质. 混合高斯模型 将一般化的EM算法流程(下载笔 ...

  10. UVA 10120 - Gift?!(搜索+规律)

     Problem D. Gift?!  The Problem There is a beautiful river in a small village. N rocks are arranged ...