原型链上的属性是否可以被修改?

date
Feb 28, 2022
slug
原型链上的属性是否可以被修改?
status
Published
tags
JavaScript
summary
type
Post

背景

近几天在读《你不知道的 Javascript》,读到一个之前理解有点偏差的知识点:原型链上的属性是否可以被修改?
我之前的理解是:会在对象本地创建这个属性并覆盖原型链上的属性。读到书中相关章节发现,这个理解不够全面,还需要考虑原型链上属性的设置,具体整理如下:

修改原型链属性的几种情况

  1. 原型链属性 writable = true
    1. 这种情况是最常见的,也是我之前理解的那样。看示例:
      const foo = {
        count: 1,
      }
      const far = Object.create(foo)
      
      console.log(far.count)  // 1
      console.log(Object.getOwnPropertyNames(far))  // []
      far.count = 2
      console.log(foo.count)  // 1
      console.log(far.count)  // 2
      console.log(Object.getOwnPropertyNames(far))  // [ 'count' ]
      总结一下:读的时候,读取的原型链上的属性;修改的时候会在本对象上定义一个同名属性,并且屏蔽掉原型链上的属性。
  1. 原型链属性 writable = false
    1. 这种情况,大多数人估计也没碰到(我就是),直接看示例:
      const foo = {
        count: 1,
      }
      // 这里修改了 writable 配置
      Object.defineProperty(foo, 'count', {
        writable: false,
      })
      const far = Object.create(foo)
      
      console.log(far.count)  // 1
      console.log(Object.getOwnPropertyNames(far))  // []
      far.count = 2
      console.log(foo.count)  // 1
      console.log(far.count)  // 1
      console.log(Object.getOwnPropertyNames(far))  // []
      可以看到,修改是没有生效的!
      ⚠️ 另外请注意,如果在严格模式 'use strict'; 下,上面的代码还会报错:TypeError: Cannot assign to read only property 'count' of object '#<Object>’.
      那有解吗?我就是需要在新对象中有一个可修改的同名属性可以吗?答案是可以,使用Object.definePropertyfar 对象上面定一个 count 属性即可。
      💡
      上述特性确实令人奇怪,我的理解是 Javascript 语言是在使用过程中不断修订完善,所以会出现一些有点不太符合预期的特性。
  1. 原型链属性是一个 setter
    1. 这种情况也是很少碰到,设置了 settergetter 可能原型对象上并没有这个属性,但是可以读取和设置。看示例:
      const foo = {
        count: 1,
        set rule(val) {
          console.log(`set rule ${val}`)
        }
      }
      Object.defineProperty(foo, 'count', {
        writable: false,
      })
      const far = Object.create(foo)
      
      far.rule = 'limit 1'  // set rule limit 1
      console.log(far.rule) // undefined
      上面这个只设置了 setter 没有设置 getter ,可以看出来,并没有在本对象上面定义同名属性去覆盖。
       
      最后,我再补充说明一下,上述三种情况,属性都是基本类型,如果这个属性是对象会怎么样?
      其实对象属性本身存的是一个引用,可以看成指针,指针存储的就是一个地址,类比一下:c 语言里面就是长整形。修改引用本身就是修改一个长整形。
      修改这个对象的属性呢?那就看这个对象的这个属性的配置了,依照上面的三种情况判断即可。

© XieZhichao 2022 - 2024