【ES5—面向对象】深入理解对象属性

1 篇文章 0 订阅
1 篇文章 0 订阅

理解对象

面向对象(Object-Oriented,OO)的语言都有一个标志,那就是都有类的概念,通过类创建任意具有相同属性和方法的对象。ES5并没有类的概念,所以它的对象也与基于类的语言中的对象有所不同。

ECMAScript 的对象是无序属性的集合,想象成散列表:无非就是一组键值对,其中值可以是数据或函数。

每个对象都是基于一个引用类型创建的(涉及到原型链和继承),可以是原生类型(Array,Object,Date,RegExp等等),也可以是自定义的类型。

对象的属性类型

只有内部才用的特性(attribute)时,描述了属性(property)的各种特征。

这些特性是为了实现 JavaScript 引擎用的,因此在 JavaScript 中不能直接访问它们。为了表示特性是内部值,使用两对儿方括号来表示。

ECMAScript 中有两种属性:数据属性和访问器属性。

数据属性

特性描述
[[Configurable]]能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性
[[Enumerable]]能否通过 for-in 循环返回属性
[[Writable]]能否修改属性的值
[[Value]]包含这个属性的数据值
var person = { 
	 name: "Nicholas" 
};

以上示例中,通过字面量语法创建对象:

[[Configurable]],[[Enumerable]],[[Writable]]默认都是true;
[[Value]]特性将被设置成“Nicholas”,这个值的任何修改都反映在这个位置上。

修改对象属性的默认特性

Object.defineProperty(o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType): any

示例演示:

var person = {}; 
Object.defineProperty(person, "name", { 
	configurable: true,
	Enumerable: true,
	writable: false, 
	value: "Nicholas" 
});

注意:使用defineProperty方法时,如果不指定,则[[Configurable]],[[Enumerable]],[[Writable]]默认都是false;

异常处理

示例说明:

var person = {}; 
Object.defineProperty(person, "name", { 
	 configurable: false, 
	 value: "Nicholas" 
}); 
//抛出错误
Object.defineProperty(person, "name", { 
	 configurable: true, 
	 value: "Nicholas" 
});

特性一: 一旦把属性定义为不可配置的,就不能再把它变回可配置了,否则会抛出错误。

//抛出错误
delete person.name;

特性二: 对不可配置的属性进行操作时,在非严格模式下不会发生异常,在严格模式下回导致错误。

补充说明: Configurable为false时,除了可以修改Writable特性外,其他特性修改都会导致错误,且Writable只能是true变成false修改可以,false再变回true同样会导致错误。

测试代码如下:
在这里插入图片描述

访问器属性

  • 访问器属性不包含数据值;
  • 包含一对getter和setter函数,分别在读取和写入新值时,调用对应的函数。
特性描述
[[Configurable]]表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性
[[Enumerable]]表示能否通过 for-in 循环返回属性
[[Get]]在读取属性时调用的函数,默认值undefined
[[Set]]在写入属性时调用的函数。默认值为 undefined

如何使用

访问器属性不能直接定义,必须使用 Object.defineProperty()来定义。

var book = { 
	 _year: 2004, 
	 edition: 1 
}; 
Object.defineProperty(book, "year", { 
	 get: function(){ 
	 	return this._year; 
 	 }, 
 	set: function(newValue) { 
 		if (newValue > 2004) { 
			this._year = newValue; 
 			this.edition += newValue - 2004; 
		} 
 	} 
}); 
book.year = 2005; 
alert(book.edition); //2

注意事项

  1. 只指定 getter 意味着属性是不能写,严格模式下,会抛出错误;
  2. 只指定 setter 函数的属性也不能读,严格模式下,会抛出错误。

定如何义多个属性

Object.defineProperties(o: any, properties: PropertyDescriptorMap & ThisType): any

示例:

var book = {}; 
Object.defineProperties(book, { 
 	_year: { 
 		value: 2004 
 	}, 
 	edition: { 
 		value: 1 
 	}, 
 	year: { 
 		get: function(){
 			return this._year; 
 		}, 
	 	set: function(newValue){ 
 			if (newValue > 2004) { 
			 	this._year = newValue; 
				this.edition += newValue - 2004; 
 			} 
 	 	}
 	}
});

分析:

  • 同时创建了3个属性;
  • ‘_year’,‘edition’是数据属性;
  • ‘year’是访问器属性;

读取属性的特性

Object.getOwnPropertyDescriptor(o: any, p: string | number | symbol): PropertyDescriptor

测试代码如下:
在这里插入图片描述
‘year’访问器属性,[[Configurable]],[[Enumerable]]默认都是false;
在这里插入图片描述
‘_year’数据属性,[[Configurable]],[[Enumerable]],[[Writable]]默认都是false;
在这里插入图片描述
通过字面量语法创建的’name’数据属性,[[Configurable]],[[Enumerable]],[[Writable]]默认都是true;

框架应用

众所周知,vue2.x版本,内部正是通过Object.defineProperty()方法属性拦截的方式,把data对象里每个数据的读写转化成getter/setter,当数据变化时通知视图更新。
掌握了上面的基础之后,我们就有资本继续学习vue中如何通过发布/订阅模式,数据变化更新视图,视图变化更新数据的具体实现

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值