Property Descriptor 属性描述符,是一个普通对象,用于描述一个属性的相关信息 如图下
image.png
其代码为

  1. const obj = {
  2. a:1,
  3. b:"a"
  4. }

查看属性描述符

通过Object.getOwnPropertyDescriptor(对象, 属性名)可以得到一个对象的某个属性的属性描述符
- value:属性值
- configurable:该属性的描述符是否可以修改 ,设置为false后无法再次修改属性描述符,但为该属性重新赋值有效
- enumerable:该属性是否可以被枚举
- writable:该属性是否可以被重新赋值

修改属性描述符

如果需要为某个对象添加属性时 或 修改属性时, 配置其属性描述符,可以使用下面的代码:

  1. Object.defineProperty(对象, 属性名, 描述符);
  2. Object.defineProperties(对象, 多个属性的描述符)
  3. //这两个的区别为 第一个只能修改或添加一个属性的描述符,第二个可以修改或添加多个

示例

  1. const obj = {
  2. a:1,
  3. b:"a"
  4. }
  5. Object.defineProperties(obj,{
  6. a:{
  7. configurable:false,
  8. },
  9. b:{
  10. configurable:false,
  11. }
  12. })
  13. // 上面修改属性a的属性描述符等同于下面的代码
  14. Object.defineProperty(obj, "a" ,{
  15. configurable:false,
  16. })

重点 存取器属性

何为存取器属性

  1. <div id="box"></div>
  2. <script>
  3. const box = document.getElementById('box')
  4. console.dir(box)
  5. </script>

image.pngimage.png
如左图中这些属性的括号里都有三个点,而正常的属性(右图)都是有值的,即使没有赋值也会有null值,左图中带(…)这个都是存取器属性,左图中我挑选一些常用的元素上的存取器属性
存取器的属性值不会存储在内存中,正常属性的属性值都是存储在内存空间中的
故设置为存取器属性时,不能与**valuewritable**共同存在

怎样设置存取器属性

属性描述符中,如果配置了 get 和 set 中的任何一个,则该属性,不再是一个普通属性,而变成了存取器属性。
get 和 set配置均为函数,如果一个属性是存取器属性,则读取该属性时,会运行get方法,将get方法得到的返回值作为属性值;如果给该属性赋值,则会运行set方法。
存取器属性最大的意义,在于可以控制属性的读取和赋值。

  1. const obj = {
  2. a: 1,
  3. b: "a"
  4. }
  5. Object.defineProperties(obj, {
  6. a: {
  7. get() {
  8. return obj._a;
  9. },
  10. set(val){
  11. obj._a = val;
  12. /**
  13. * “_”为保留符号,切记此处不能使用 obj.a=val;因为现在属性a为存取器属性
  14. * 存取器属性的读取与赋值都会调用其对应得函数,此处为赋值,假设此处写的是obj.a=val;那吗不就再次
  15. * 调用自己的赋值函数吗(存取器属性的赋值为set()) 这样不就是无限递归吗,会导致栈溢出
  16. * */
  17. }

注意: “_”为保留符号,切记此处不能使用 obj.a=val;因为现在属性a为存取器属性,存取器属性的读取与赋值都会调用其对应得函数,此处为赋值,会运行set方法,假设此处写的是obj.a=val; 这句代码的意思不就是为属性a赋值吗,但是a现在为存取器属性,他会调用set方法,这样不就重新调用set方法,依次往后,无限调用set方法,不就无限递归啦,最后栈溢出。
当get与set方法中啥都不写的话,返回值为unfinished,你重新复制与读取都是unfinished,函数的默认返回值为unfinished

案例1 控制年龄的最小值与最大值

  1. <p>
  2. <span>姓名:</span>
  3. <span id="name"></span>
  4. </p>
  5. <p>
  6. <span>年龄:</span>
  7. <span id="age"></span>
  8. </p>
  9. <script>
  10. const spanName = document.getElementById("name")
  11. const spanAge = document.getElementById("age")
  12. const user = {}
  13. Object.defineProperties(user, {
  14. name: {
  15. get() {
  16. return spanName.innerText;
  17. },
  18. set(val) {
  19. spanName.innerText = val;
  20. }
  21. },
  22. age: {
  23. get() {
  24. return +spanAge.innerText;
  25. },
  26. set(val) {
  27. if (typeof val !== "number") {
  28. throw new TypeError("年龄必须是一个数字")
  29. }
  30. if (val < 0) {
  31. val = 0;
  32. } else if (val > 200) {
  33. val = 200;
  34. }
  35. spanAge.innerText = val;
  36. }
  37. }
  38. })