面向对象(一)

128 阅读3分钟

对象的概念

对象Javascript中一个极其重要的概念,可以说Javascript中万物皆对象。对象可以将多个相关联的数据封装到一起,以便更好地表述一个事物。

  • 比如我们要描述一辆车:Car,那么它有哪些数据呢?大小(size)品牌(brand)价格(price)高度(height)等等。 所以我们可以将这些信息抽象成一个对象来表达:
   const Car = {
     brand: 'Benz',
     size: 'large',
     price: '1,000,000',
     height: '1.8'
   }

那么创建一个Javascript对象有哪几种方式呢?有两种方式:

  • new创建
  • 字面量创建
  • Object.create创建
   // new创建
   const obj1 = new Object()
   obj1.name = 'zengge'
   obj1.age = 22
   
   // 字面量创建
   const obj2 = {}
   obj2.name = 'zengge'
   obj2.age = 22
   
   // Object.create
   const newObj = Object.create (null, {
     name: {
       value: 'zengge',
       enumerable: true
     },
     age: {
       value: 22,
       enumerable: true
     }
   })

其实这三种方法创建对象并没有什么很大的区别,因为第二种字面量创建对象写法简单而且易读,所以我们更推荐第二种写法。

对象的操作

首先最常见的对象操作就是增删改查了

   const obj = {
     name: 'zengge',
     age: 22
   }
   
   // 增加属性
   obj.size = 'large'
   
   // 删除属性
   delete obj.size
   
   // 修改属性
   obj.name = 'zengdada'
   
   // 查看属性
   console.log(obj.name)

如果我们现在想要对obj对象进行更加精准的控制,比如不允许某一个属性被赋值或者不允许某一个属性被遍历,那么应该怎么办呢?我们需要用到Object.defineProperty

Object.defineProperty(obj, prop, descriptor)
可以接收三个参数:

  • obj是要定义的对象
  • prop是要定义或者修改的属性的名称或者Symbol
  • descriptor要定义或修改的属性描述符 我们提到了属性描述符,什么是属性描述符属性描述符(Property Descriptor)是 ES5 之后出现的概念,顾名思义,它用于描述属性应该是什么样,例如是否只读,能否枚举,能否可配置等。所有对象属性均可使用属性描述符来定义。 属性描述符的类型有两种:
  • 数据属性(Data Properties)描述符
  • 存取属性(Accessor Properties)描述符

数据属性描述符

数据属性有4个描述其行为的特性:

  • 可配置性[[Configurable]]: 表示能否通过delete删除属性,能否修改属性特性,能否把数据属性修改为访问器属性。
  • 可枚举性[[Enumerable]]:表示能否通过for-in循环返回属性。
  • 可写入性[[Writable]]:表示能否修改属性值。
  • 属性值[[Value]]:表示属性值。 这样说会有点抽象,我们来写一段代码来解释一下:
可配置性[[Configurable]]
   const obj = {
     name: 'zengge',
     age: 22
   }
   
   Object.defineProperty(obj, 'size', {
     value: 'large', // 设置值
     configurable: false // 不可配置,也就是说不可删除和不可修改
   })
   for(let i in obj) {
     console.log(i)
   }
   console.log(Object.keys(obj))
   delete obj.age
   console.log(obj.age)
   delete obj.size
   console.log(obj.size)

image.png
我们看到这里删除age属性成功,而删除size属性失败了,依然打印出了large。

可枚举性[[Enumerable]]
   const obj = {
     name: 'zengge',
     age: 22
   }
   
   Object.defineProperty(obj, 'size', {
     value: 'large', // 设置值
     enumerable: true // 不可枚举,for-in无法遍历属性,Object.key也无法遍历属性
   })
   for(let i in obj) {
     console.log(i)
   }
   console.log(Object.keys(obj))

image.png
可以看到size属性并没有被遍历出来,因为我们将enumerable设置为true

可写入性[[Writable]]
   const obj = {
     name: 'zengge',
     age: 22
   }
   
   Object.defineProperty(obj, 'size', {
     value: 'large', // 设置值
     writeable: false // 不可修改,不能写入新值
   })
   obj.size = 'small'
   console.log(obj.size)

image.png
我们尝试修改objsizesmall,但是失败了,size依然是large,因为我们配置了writeablefalse

存取属性描述符

存取属性描述符是由一对 getter-setter 函数功能来描述的属性,如下图代码:

   const obj = {
     name: 'zengge',
     age: 22,
     _size: 'large'
   }
   
   Object.defineProperty(obj, 'size', {
     enumerable: true,
     configurable: false,
     get: function() {
       return this._size
     },
     set: function(value) {
       this._size
     }
   })

这样的话我们外部如果要获取size属性或者修改size属性,那么会经过getset函数,可以在这回两个函数中进行额外的操作。注意当存在存取属性描述符时,数据属性描述符的value值是不可以设置的,这样会导致报错。