侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

js对象中的属性类型

2024-05-13 星期一 / 0 评论 / 0 点赞 / 79 阅读 / 5357 字

ECMA-262在第五版定义只有内部才有的特性时,描述了属性的各种特征,这些特性时为了实现javascript引擎用的,因此在javascript中不能直接访问他们. ECMAScript中有两种属性

ECMA-262在第五版定义只有内部才有的特性时,描述了属性的各种特征,这些特性时为了实现javascript引擎用的,因此在javascript中不能直接访问他们.

ECMAScript中有两种属性,数据属性跟访问器属性.

1.数据属性

数据属性包含一个数据值的位置.在这个位置可以读取和写入值,数据属性有4个描述其行为的特性.

  • [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,即更改该属性的其他特性,或者能否把属性修改为访问器属性,默认值为true.值得一说的是,一旦将该属性设置成false之后,就无法重新设置成true.
  • [[Enumerable]]:表示能否通过for-in循环返回属性,默认为true.
  • [[Writable]]:表示能否修改属性的值,默认为true
  • [[Value]]:属性的值,读取属性值的时候,从这个属性读,写入属性值的时候,把新值保存在这个位置,默认值为undefined.
var person = {    name : "Rainn",    age : 25,    job : "IT"};Object.defineProperty(person,"name",{    writable : false,});Object.defineProperty(person,"age",{    writable : false,    enumerable : false,});Object.defineProperty(person,"job",{    configurable : false})person.name = "test";person.age = 18;person.job = "Singer";alert(person.name);   //Rainnalert(person.age);    //25alert(person.job);    //Singerfor(var p in person){	console.log(person[p])}//Rainn//Singer

name跟age 都设置了不可写,所以返回结果还是之前定义的值,age设置了不可循环出来,所以最终循环出来的结果,把age跳过去了.

因为name并没有设置不可配置,所以这个时候可以更改name的数据属性,达到重新写入的目的,而因为job设置了不可配置,所以,再操作任何job的数据属性,都会抛出一个错误

Object.defineProperty(person,"name",{    writable : true});person.name = "test";alert(person.name); //testObject.defineProperty(person,"job",{    configurable : true}); //Uncaught TypeError: Cannot redefine property: job

上述写法,太麻烦?是的.设置单一属性的时候用defineProperty,而设置多属性的时候,可以直接用defineProperties,也建议这么写,这样代码维护的时候也比较方便,以上代码可以写作

Object.defineProperties(person,{    name : {        writable : false,        configurable : false    },    age : {        writable : false,        enumerable : false    },    job : {        configurable : false    }})

2.访问器属性

访问器属性不包含数据值,包含一对getter和setter函数,两个函数都不是必要的,默认值均为undefined,在读取访问器属性时,会先调用getter函数,在写入访问器属性时,会先调用setter函数,并传入新值,类似某些语言的魔术方法__GET跟__SET,只是这里只控制单一属性.同样的,访问器属性,也有4个特性,其中Configurable跟Enumerable跟数据特性一样,这里不再细说.

先看一段错误代码:

var person = {    name : "Rainn",    age : 25}Object.defineProperties(person,{    name : {        get : function(){            return "hello! I'm " + this.name;         },        set function(newValue){            this.name = newValue + "(changed)";        }    },    age : {        get : function(){            return "18 forever";        },        set : function(){            this.age -= 1;        }    }});

如果代码这么写的话,会报出堆栈溢出,原因在于,读name的时候,会访问get,get中继续读了this.name,就会无限读,造成堆栈溢出,所以,一般用一个替代的属性处理,习惯性的用_+属性名表示.,用于表示只能通过对象方法访问的属性

var person = {};Object.defineProperties(person,{	_name : {		value : "Rainn",		writable : true,	},	_age : {		value : 25,		writable : true,	},	name : {		get : function(){			return this._name;		},		set : function(newValue){			this._name = newValue + '(used)';		}	},	age : {		get : function(){			return '18 forever';		},		set : function(){			this._age -= 1;		}	}});alert(person.name);   //Rainnperson.name = "Tom";  alert(person.name);   //Tom(used)alert(person.age);    //18 foreverperson.age = 18;person.age = 18;alert(person._age);   //23

这里还有一点需要提出来 ,在申明对象是,如果在自变量中声明了属性,则这个属性的数据特性都是默认true,即使更改其中某一项,其他的还是true,而如果在声明对象的时候,自变量中没有定义的属性,则均默认为false;

查看属性特性的方法为Object.getOwnPropertyDescriptor()

var person = {	name : "rainn"};Object.defineProperties(person, {	name : {		writable : false	},	_age : {		value : 25	}})var nameDes = Object.getOwnPropertyDescriptor(person,'name');var ageDes = Object.getOwnPropertyDescriptor(person,'_age'); console.log(nameDes); //{value: "rainn", writable: false, enumerable: true, configurable: true}console.log(ageDes);  //{value: 25, writable: false, enumerable: false, configurable: false}

 

广告 广告

评论区