属性修饰符 | 青训营

前言

大家好!我是江南功,下面讲讲开发中可能会遇到的问题,话不多说,接招?

问题描述

const smallblack={

name: '张三',
age: 18,
sex: '男'
}


这里有个对象smallblack,是一些个人信息的对象.但是发现要用这个对象的时候缺少了一个属性brithday,那么如何给其添加属性呢,小林同学二话不说写出如下代码:

// 构造函数
function PersonInfo(val){
    this.data = val
    this.brithday = '2022-10-11'
}




// 或者是ES6的写法
class PersonInfo{
constructor(val){
   this.data = val;
   this.brithday = '2022-10-11'
}
}

我们来看看ES6的写法,其中的一行代码this.data = val,会使得我们有个危机感,什么危机感呢?就是这行代码不够严谨不够稳,容易出现问题,会出什么问题呢?

const p = new PersonInfo(smallblack)
console.log(p)
// PersonInfo {
//  data: { name: '张三', age: 18, sex: '男' },
//  brithday: '2022-10-11'
// }



// 但是进行如下操作
p.data = 'null'
console.log(p)
// PersonInfo { data: 'null', brithday: '2022-10-11' }

p.data = 'null'这行代码将一个对象改为了字符串’null’,你一不小心改动了,那么整个数据就用不了了,因为被你重新赋值了!这就会产生一些不可预料的问题.那么我们就希望这个p.data不能修改,如何做到呢?因此我们就引出了属性描述符,本文将围绕它进行展开!

什么是属性描述符

const obj = {
a: 1,
b: 2
}

上述obj对象的a属性我们可以整么描述呢?

  1. 值为1
  2. 可以重新赋值
obj.a =10
console.log(obj.a) // 10
  1. 可以被遍历
for (const key in obj) {
  console.log(key)
}
// a
// b

以上三个特点描述就是属性描述符,当然我们可以通过js中提供的函数Object.getOwnPropertyDescriptor来获取属性描述:

const aDesc = Object.getOwnPropertyDescriptor(obj, 'a')
console.log(aDesc)
// { value: 1, writable: true, enumerable: true, configurable: true }

上述代码打印出来的就是属性描述符的具体信息.实际上每个属性都有一套对象来描述自身,而且这个对象是可以修改的.那么如何更改呢?

js中提供了一个函数Object.defineProperty,是不是大家对这个函数很熟悉呢?没错在vue2中的响应式原理就用到了这个函数,大家如果对vue2的响应式原理感兴趣可自行百度,这里不再展开.

// 该函数是用来设置属性描述符
Object.defineProperty(obj, 'a', {

  value: 10, // 设置值
  writable: false, // 不可重写
  enumerable: false // 不可遍历
})

在上述代码中value是设置obj属性a的值,writable则表示属性a是否可以重新被赋值,而enumerable则表示属性a是否可以被遍历.当writable为false不可重写时,enumerable为false,不可遍历时,如下代码所示:

// 当属性a 不可重写时
obj.a = 'abc'
console.log(obj.a) // 10

// 当属性a 不可遍历时
for (const key in obj) {
  console.log(key)
} // b

const keys = Object.keys(obj)
console.log(keys) // ['b']

console.log(obj) // { b: 2 }

configurable表示属性描述符本身是否可以被修改,如下代码:

Object.defineProperty(obj, 'a', {
  value: 10, // 设置值
  writable: false, // 不可重写
  enumerable: false, // 不可遍历
  configurable: false // 不可修改属性描述符本身
})




// 我在重新定义a的属性描述符
Object.defineProperty(obj, 'a', {
  writable: true, // 可重写
  enumerable: false, // 不可遍历
  configurable: false // 不可修改属性描述符本身
})
// 报错----------------------

运行上述代码会报错,因为configurable已经设置为false了,此时不可再重新定义a的属性描述符.

image.png

好的,讲到这里我们再回到前面的问题.稍微改下代码:

const smallblack={

  name: '张三',
  age: 18,
  sex: '男'
}




class PersonInfo {
  constructor(val) {
    Object.defineProperty(this, 'data', {
      value: val,
      writable: false,
      configurable: false
    })
  }
}


const p = new PersonInfo(smallblack)

p.data = 'null' // 无效
console.log(p.data)
// { name: '张三', age: 18, sex: '男' }

上述代码中属性data无法被重新赋值,这样就解决了问题.但是完全解决了吗?没有举个例子:当我代码写了一大串后,其中有修改这个data属性,由于时间过的太久了,早就忘了data是无法修改的,这就使得你编写的代码会出现一些问题;再者说你的同事拿到这一大段代码,同事想当然的认为data属性是可以修改的,就写了类似于p.data = 'null'的代码,发现没有生效,瞬间懵逼了!找了半天都没有解决,想了半天都没弄明白,气得口吐芬芳……最后还是原先编写这段代码的同事说明这个data属性不能被修改,找了半天问题的同事无奈地说,大哥你能写个报错程序来提示其他人注意这个data属性不能修改吗?

为了使这段代码程序更加可读可维护,我们应该给其添加报错程序.那么我们就要介绍Object.defineProperty的getter函数和setter函数了.

getter函数:当属性被读取时触发;setter函数:当属性被设置时触发.

const obj = {}
Object.defineProperty(obj, 'a', {

// 读取器
  get: function () {
    console.log('handle getter')
    return 123
  },
// 设置器
  set: function () { 
    console.log('handle setter')
  }
})
console.log(obj.a)
// handle getter
// 123


obj.a = 1 + 1 // 触发set(1+1)
console.log(obj.a) // 相当于console.log(get())     123

obj.a = obj.a + 1
console.log(obj.a) // 123

最终代码

好的,基本了解getter和setter后,我们着手解决下如何写个报错程序来提示其他人注意这个data属性不能修改:

// 
const smallblack = {
  name: '张三',
  age: 18,
  sex: '男'
}



class PersonInfo {
  constructor(val) {
    Object.defineProperty(this, 'data', {
      configurable: false,
      get: function () {
        return val
      },
      set: function () {
        // 错误处理
        throw new Error('the data is not redined!')
      }
    })
  }
}

const p = new PersonInfo(smallblack)
p.data = 'null' // 报错
console.log(p.data)

执行上述data属性重新赋值代码报错,这样代码虽然写多了,但整体上代码的可读性增强了,也便于后人维护,减少不必要的交流成本.

image.png

总结

好了,问题解决了.总结一下吧.首先上述解决问题的思维能力在我们写业务代码是比较难形成的,只有写一些组件,第三方库等等才能培养出这种能力!少年易学老难成,一寸光阴不可轻.诸位共勉!

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYKlvJqi' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片