Basics of Object.defineProperty

Object.defineProperty this method familiar to everyone, you can add or modify operations on the object's properties. That data can be hijacked. vue is through this method to hijack data.

Usually when we create an object, usually by object literal way to create:

var student = {
  name:"小明",
  age:10    
}
Properties of an object when it is created, all with some of the characteristic values ​​(characteristic), JS to define their behavior through these characteristic values. 
 
ECMA-262 5th edition defined only used only inside characteristic (attribute), describe various characteristic properties (Property) of.
ECMA-262 defines these characteristics are used to achieve JavaScript engine, so the JavaScript can not directly access them.
To show an internal characteristic value, it puts them in this specification two pairs of children square brackets, for example [[Enumerable]].
 
ECMAScript There are two properties: the data access attributes and properties.
 
                    ------------- "JavaScript Advanced Programming (third edition)" Chapter VI
Attribute descriptor
 
On the MDN, for the attributes of the object when it is created, with the characteristic values, it is called the attribute descriptor . It contains data descriptor and access descriptor .
 
a) a data attribute (data descriptor):
  1. [[Configurable]]: Delete to delete the property can be passed, the ability to modify the characteristics of the property, or the property can be modified to access the properties.
  2. [[Enumerable]]: Can enumerated by for ·· in or Object.key ().
  3. [[Writable]]: whether the value of the property to be modified.
  4. [[Value]]: The value of the property can be any valid JavaScript value (numeric, objects, functions, etc.)
b) Access properties (Access Descriptor): 
  1. [[Configurable]]: Delete to delete the property can be passed, the ability to modify the characteristics of the property, or the property can be modified to access the properties.
  2. [[Enumerable]]: Can enumerated by for ·· in or Object.key ().
  3. [[Get]]: function called when read attribute.
  4. [[Set]]: function called when writing property.
 
The default value of the attribute descriptor: There are two cases

 1)  When using the object literal or constructor form creation attributes time, enumerable, configurable, writable are true, value, get, set are undefined. So usually when the object is defined, we are free to CRUD.

2) When using Object.defineProperty, Object.defineProperties or Object.create case where a function of adding an attribute . enumerable, configurable, writable are false; value, get, set are undefined.

  By Object.getOwnPropertyDescriptor (object name, attribute name) to get the default value of the attribute descriptor .

  Object.defineProperty :

  Object.create :

 

How to modify the default attribute defaults?

这种两个方括号 [[ ]] 的方式,我感觉就和指向对象的原型的指针类似,ECMA-262 第 5 版 称这个指针为 [[prototype]] ,也是没有标准的方式访问,但是主流浏览器都提供了__proto__属性来访问。

这上面的属性描述符都有自己的默认值,但是如果我想修改某些数据描述符的默认值呢?它并不能直接访问啊,比如 obj.age.[[Enumerable]] 这样是不行的。既然不能直接访问,那么我怎么去修改对象中某些属性的指定特性呢?

以前可以使用非标准的方式:  对象.__defineGetter__( "属性", function(){} )  或者  对象.__defineSetter__( "属性", function(){} )  。不过这方法已经被废弃了,虽然有些浏览器还支持,但是不建议使用

这时候就需要用到 Object.defineProperty 这个方法了。 

语法:Object.defineProperty(obj,prop,descriptor)
  1. obj,即需要修改属性的对象。必填。
  2. prop,需要修改的属性。必填。
  3. descriptor,属性修饰符配置项,是个对象。属性修饰符不填的情况下,这个参数也不能少,最少也要是一个 { } 空对象。
  4. 最终返回处理后的 obj 对象
descriptor 也是分数据描述符存取描述符。功能也是一样
a) 数据描述符:
  1.  configurable 
  2.  enumerable 
  3.  writable 
  4.  value

b) 存取描述符

  1.  configurable
  2.  enumerable 
  3.  get 
  4.  set

上面的这些属性都是可以直接访问配置的。

数据描述符和存取描述符用法都很简单。不过需要注意的是:

  1. 数据属性符的writable或value 与 存取描述符的get或set不能同时存在 。会报错。
  2. 存取描述符的get与set也可以不同时存在,如果只指定get表示属性不能写(意思进行赋值操作,最后属性还是为undefined,即使最初属性定义了初始值),只指定set表示属性不能读(意思是获取属性的时候是undefined,整个对象都为{ }。即使最初定义了一些属性的)。 
  3. 存取描述符的get与set是个函数,函数里的 this 指向的是 需要修改属性的对象即obj

还有个Object.defineProperties() 可以劫持多个属性。有兴趣的可以去 MDN 看看

如果对象的属性中还有对象,那么这时候需要深层遍历,一般的方法是:

var obj = {
    name:"zjj",
    sex:'male',
    money:100,
    info:{
        face:'smart'
    }
}

observe(obj)
console.log(obj)
obj.sex
= 'female' obj.info.face = 20; obj.info.hobit = 'girl';
console.log(obj)
function observe(target){ if (!target || typeof target !== 'object') return; Object.keys(target).forEach(function(val){ defineProp(target,target[val],val) }) } function defineProp(curObj,curVal,curKey){ observe(curVal) //再次遍历子属性 Object.defineProperty(curObj,curKey,{ enumerable:true, configurable:true, get:function(){ console.log('获取了属性',curVal) return curVal }, set:function(newData){ console.log('设置了属性',newData) curObj = newData; } }) }

 

这样,目标对象中的属性的值为对象的时候也能进行数据劫持了。不过我疑惑的点是:添加不存在的属性时,为什么调用的是get方法???后面搞懂了再来解决这个问题

 

Object.defineProperty的缺点:

  1. 无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。所以vue才设置了7个变异数组(push、pop、shift、unshift、splice、sort、reverse)的 hack 方法来解决问题。
  2. 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。如果能直接劫持一个对象,就不需要递归 + 遍历了。所以 vue3.0 会使用 Proxy 来替代Object.defineProperty

 

Proxy:代理

  听说vue3.0 会用 proxy 替代 Object.defineProperty()方法。所以预先了解一些用法是有必要的。

  proxy 能够直接 劫持整个对象,而不是对象的属性,并且劫持的方法有多种。而且最后会返回劫持后的新对象。所以相对来讲,这个方法还是挺好用的。不过兼容性不太好。

  关于proxy的介绍与用法,可以看看 阮一峰老师的 这篇文章

  

 

题外话:ECMAScript  与  JavaScript  的关系

参考:这里

Netscape 公司最初创建了一个用于浏览器的脚本语言,后与Sun 公司(创建了Java)联合发布了该脚本语言,命名为Javascript;后来微软也出了一个 JScript,用于IE3.0浏览器;还有Cenvi的ScriptEase。于是Netscape 公司决定将 JavaScript 提交给国际标准化组织 ECMA,希望 JavaScript 能够成为国际标准。

1997年7月,ECMA的TC93(39号技术委员会)发布262号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准。由于商标和其它协议的原因,只有Netscape 公司能使用Javascript 这个名称,所以最后将这种语言称为 ECMAScript。而现在我们所说的 JavaScript 是 ECMAScript + DOM + BOM的集合。DOM和BOM是W3C制定的规范。

现在说的ES5就是 ECMAScript 5.0版,而ES6就是 ECMAScript 6 后更名为 ECMAScript 2015(简称ES2015),后面每一年的6月份都会发布一个新的版本,不过增加的内容并不多。ES7(ES2016)、ES8 (ES2017)、ES9 (ES2018),现在2019.7月了,这个时候都已经出了ES10(ES2019)。不过ES10还是一个草案,并没有多少浏览器支持。主流的都是ES5 和 ES6。 

 

Guess you like

Origin www.cnblogs.com/zjjDaily/p/11227623.html