JavaScript 学习笔记 之 对象 (三) - [[Get]]和[[Put]]操作

[[Get]]

对对象属性的访问看起来似乎是一件很简单的事

但事实上这里有个复杂的[[Get]]操作在里面(可以理解为函数调用[[Get]]() )

对象默认的内置[[Get]]操作首先是在对象中查找是否有名称相同的属性,有则返回这个属性的值

如果没有找到,则会遍历可能存在的[[Prototype]]链(也就是原型链,之后我会专门再出一系列博客来介绍这个)

如果无论如何都没找到,name就返回一个undefined值

如果你还记得我在写关于作用域的学习笔记的话,你可能会发现这里跟变量访问(RHS查询)有点不太一样

变量访问没找到的话会抛出一个ReferenceError异常,而对象属性的访问没找到则会返回一个undefined值

不过这里有个问题

如果属性设置的值就是undefined呢?

所以直接通过返回值无法判断这个属性是否存在,但是有另外的方法可以判断(in,hasOwnProperty(..),稍后会详细介绍)

[[Put]]

[[Put]]操作并不仅仅只是给对象设置或者创建一个属性

[[Put]]被触发时,实际行为取决于许多因素,但是最重要的因素是对象中是否已经存在这个属性

如果存在这个属性,[[Put]]会检查一下内容

  1. 属性是否是访问描述符(接下来会讲到)?如果是并存在setter就调用setter
  2. 属性的数据描述符中的writable参数
  3. 如果都不是,则将该值设定为属性的值

如果不存在的话,那么操作会更加复杂,这个我们在讲原型链的时候再详细讨论

访问描述符

属性不一定包含的是值

他们可能是具备getter/setter的"访问描述符"

在ES5中可以使用getter和setter来部分改写默认操作,但是只能应用在单个属性上

getter和setter都是隐藏函数,会做获取和设置函数值的时候调用

当年给一个属性定义setter和getter时,这个属性会被定义为访问描述符

而此时JavaScript将会忽略属性(数据描述符中)的value和writable特性,而关心set和get(还有configurable和enumerable特性)

		var obj = {
			get a() {
				return 2;
			}
		}
		obj.a = 10086
		console.log(obj.a); //2

由于get和set同样是属性描述符(数据描述符和访问描述符)中,我们也可以用定义属性描述符的方式来定义他们

		var obj = {
			a: 1
		}
		Object.defineProperty(obj, "a", {
			get: function() {
				return 233
			},
			enumerable: true //确保a会出现啊属性列表中
		});
		obj.a = 111;
		console.log(obj.a); //233

这两种方式都会在对象中创建一个不包含值的属性 a,对于这个属性a 的访问会自动调用一个隐藏函数,他的返回值会被当做属性访问的返回值

由于我们只定义了getter,所以对a的值进行设置时set会忽略赋值操作,不会抛出错误

setter方法的设置跟getter是一样的,不过他接受一个参数,也就是赋值操作传递进去的参数

		var obj = {
			a: 1
		}
		Object.defineProperty(obj, "a", {
			get: function() {
				return this._a_;
			},
			set: function(val) {
				this._a_ = val + ",这是setter设置的"
			}
		});
		obj.a = 111;
		console.log(obj.a); //111,这是setter设置的

注 : 这个案例中的_a_只是一种惯例,其实在对象内创建了一个新的值,没有任何特殊的行为

猜你喜欢

转载自blog.csdn.net/Aproducer/article/details/82657740
今日推荐