JavaScript——数据属性和访问器属性

我们都知道,在javascript中通过var obj = {name: "dancy"} 可直接创建一个对象。

当我们需要取值时,直接使用obj.name就能获取到该对象name属性的值。
当我们需要修改对象的属性值也只要 obj.name = "lotus" 就能实现我们想要的结果。
当我们需要删除该对象的属性时,直接 delete obj.name 就可以了。
当我们需要获取对象所有的属性和值,直接使用 for in即可。

我们对于对象的各种操作已经非常熟悉了,但,在对对象进行各种操作的同时,是否有想过:

  • 为什么我们可以进行这些操作?
  • 我们是否可以控制对象的某种属性不能被修改?
  • 如何禁用这些操作?

在ECMAScript 中有两种属性:数据属性和访问器属性。当我们弄懂什么是数据属性,什么是访问器属性的时候,上面的那些问题就不复存在了。

一、数据属性

数据属性有四个,它们分别是 configurable、enumerable、writable、value 。对于这几个数据属性的定义,这里引用《javascript高级程序设计(第3版)》中的描述。

configurable: 表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。默认为true。
enumerable:表示能否通过 for-in 循环返回属性。默认为true。
writable: 表示能否修改属性的值。默认为true。
value:属性的数据值。默认为undefined。

接下来,我们尝试理解上面这些描述的含义。首先,我们先创建一个如下所示的对象:

var obj = {
	name: "dancy",
	age: 23
}

1. configurable

根据configurable的定义,我们通过 Object.defineProperty 修改obj的name属性的数据属性configurable 为false。

Object.defineProperty(obj, "name", { 
 configurable: false
});

根据定义, configurable为false时,我们不能通过 delete 删除属性,不能修改属性的特性,不能把属性修改为访问器属性。接下来,我们做以下尝试:

尝试一:删除obj的name属性
在控制台测试结果:
在这里插入图片描述

尝试二:修改属性的特性
在控制台测试结果:
在这里插入图片描述
当我们把对象属性的configurable属性改为false之后,就不能再将其改回true了,同时对于enumerable属性的修改也受到限制,当我们尝试修改时,会报错!

2. enumerable

根据定义,我们重新定义obj对象并修改其name属性的enumerable为false,然后用for in遍历obj对象。

Object.defineProperty(obj, "name", { 
 enumerable: false
});
for(var key in obj) {
	console.log(key + "——" + obj[key])
}

控制台测试结果:
在这里插入图片描述
因为属性name的enumerable改为了false,所以在使用for in遍历obj对象时,我们无法遍历到name属性,所以上面的代码只打印出了属性age。

3. writable和value

value属性的值能否被修改是根据writable确定的,如writable为true,则value可以被修改,否则不能被修改。当writable为false时尝试修改value同样会报错。
我们将writable改为false,然后修改name的值为lotus,再控制台输出结果如下:
在这里插入图片描述

所以,当writable为false时,我们无法修改name属性的值。这里需要注意的是,如果name属性的configurable为false,此时我们可以将writable的值改为false,但如果再想将writable改为true时会报错!!!

但如果configurable为true的话,我们就可随意修改writable。
在这里插入图片描述

二、访问器属性

访问器属性也有四个,它们分别是 configurable、enumerable、get、set 。其中configurable和enumerable的作用和数据属性中的作用相同,这里不再继续说明。

get:在读取属性时调用的函数。默认值为 undefined。
set:在写入属性时调用的函数。默认值为 undefined。

同理,我们可以使用 Object.defineProperty对访问器属性进行定义。以上面的obj对象为例。

Object.defineProperty(obj, "name", { 
 get: function(){ 
 	return this._name; 
 },
 set: function(newValue){ 
 	if(typeof newValue === 'number') {
		this._name = 'this is a number';
	} else {
		this._name = newValue;
	}
 	
 }
}); 

测试结果:
在这里插入图片描述

细心的小伙伴肯定发现了,我在定义get和set使用的是_name,而不是直接使用的name,这是因为我们在obj.name = 123 触发set函数时,set函数内部同时也触发了get方法,所以导致栈溢出错误,无法直接使用name,具体可以参考这篇文章 https://www.jianshu.com/p/043c11ec2e33

需要注意的是,访问器属性不能直接定义,必须使用 Object.defineProperty()来定义。

还有就是,我们不一定非要同时定义get和 set。但只指定 get 意味着属性是不能写,尝试写入属性会被忽略。在严格模式下,尝试写入只指定了 get函数的属性会抛出错误。

类似地,只指定 set函数的属性也不能读,否则在非严格模式下会返回 undefined,而在严格模式下会抛出错误。

当我们需要对属性取值或修改行为进行控制时,控制访问器属性set和get变能满足我们的需求了。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值