重学javaScript (十七)|面向对象中的Object.defineProperty()

115 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情

前言

前面文章说道,在javascript中函数是第一公民,但在js不仅支持函数式编程,也支持面向对象的编程,在js中的对象是一个由键值对组成的无序集合,也就是key-value,其中key是标识,value可以是任何的值,也包括函数,当值为函数时,这个函数就是对象的方法。

创建对象的两种方式

  • 使用对象字面量进行创建
let obj = {
    name: 'juejin',
    age:22
}
  • 通过new一个Object类的实例来创建对象
let obj = new Object()
obj.name = 'juejin'
obj.age = 22

这两种方式创建的对象都是一样的

对象属性的具体控制:Object.defineProperty()

Object类上有一个defineProperty的方法可以对对象的属性进行控制,接下来我们来一起看下吧

mdn上是这么定义的: Object.defineProperty()  方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,

语法

Object.defineProperty(obj, prop, descriptor)

参数

它接收入三个参数:

  • obj:需要进行操作的对象
  • prop:操作的对象需要定义或修改的属性的名称
  • descriptor:具体的操作内容的对象

descriptor

在descriptor的对象中,分为数据属性描述符存取属性描述符两类,我们接下来分别具体介绍下

属性configurableenumerablevaluewritablegetset
数据属性描述符可以可以可以可以不可以不可以
存取属性描述符可以可以不可以不可以可以可以

数据属性描述符

从上述的表格中我们可以看出来属性操作符有configurable,enumerable,value, writable可以使用,get和set不可以,我们来具体看下每个属性都是什么作用

configurable:

可以控制属性删除和是否可再次进行属性操作,默认值时false(使用new关键字创建对象时)

  • 当首先设置为true的时候可以被删除
        var obj = {
            name:'juejin'
        }

        Object.defineProperty(obj,'name',{
            configurable:true
        })
        //删除属性
        delete obj.name
        console.log(obj.name) //undefined
  • 设置为false的时候不可以被删除
        var obj = {
            name:'juejin'
        }

        Object.defineProperty(obj,'name',{
            configurable:false
        })
        //删除属性
        delete obj.name
        console.log(obj.name) //juejin
  • 当设置为true的时候可以被修改特性
        var obj = {
            name: 'clearlove'
        }
          Object.defineProperty(obj, "name", {
            writable: false,
            enumerable: true,
            configurable: true
        });
        //重新修改特性
        Object.defineProperty(obj, "name", {
            writable: true,
            enumerable: true,
            configurable: true
        });
        console.log(obj.name); //clearlove
  • 当设置为false的时候不可以修改特性
var obj = {
    name: 'juejin'
}
//重新修改特性
Object.defineProperty(obj, "name", {
    configurable: false
});

Object.defineProperty(obj, "name", {
    configurable: true
});
console.log(obj.name); 

image.png

enumerable

表示该属性是否可以被枚举,默认值时false(使用new关键字创建对象时)

  • 当设置为true的时候可以被枚举
var obj = {
    name: 'juejin',
    age: 22
}
//修改特性
Object.defineProperty(obj, "name", {
    enumerable:true
});

// 进行枚举操作
let keys = Object.keys(obj)
console.log(keys)

image.png

  • 当设置为false的时候不可以被枚举
var obj = {
    name: 'juejin',
    age: 22
}
//修改特性
Object.defineProperty(obj, "name", {
    enumerable:false
});

// 进行枚举操作
let keys = Object.keys(obj)
console.log(keys)

image.png

value

就是设置属性的值 默认值为undefined (使用new关键字创建对象时)

var obj = {
    name: 'juejin',
    age: 22
}
//修改特性
Object.defineProperty(obj, "name", {
    value: 'kaka'
});

console.log(obj.name)

image.png

注意:它不能和get同时使用

writable

表示是否可修改的对象的属性,默认值时false (使用new关键字创建对象时)

  • 设置为true的时候可以修改属性
var obj = {
    name: 'juejin',
    age: 22
}
//修改特性
Object.defineProperty(obj, "name", {
    writable: true
});

obj.name = 'kaka'

console.log(obj.name)

image.png

  • 设置为false的时候不可以修改
var obj = {
    name: 'juejin',
    age: 22
}
//修改特性
Object.defineProperty(obj, "name", {
    writable: false
});

obj.name = 'kaka'

console.log(obj.name)

image.png

存取属性描述符

它主要是指get和set,是指在对对象的属性进行存取的时候可以做一些操作

get

在属性值被获取的时候进行的操作

  let obj = {
    name: 'juejin',
    age: 22
}
//修改特性
Object.defineProperty(obj, "name", {
   get(){
    console.log('我被获取了')
    return 'juejin'
    // return 'kaka'
   }
});

console.log(obj.name)

可以用来保护某个属性,例如不让获取name的真实值

let obj = {
    name: 'juejin',
    age: 22,
    _name: 'kaka'
}
//修改特性
Object.defineProperty(obj, "name", {
   get(){
    return obj._name
    // return 'kaka'
   }
});

console.log(obj.name)

image.png

set

当对属性设置值时,进行的操作

let obj = {
    name: 'juejin',
    age: 22,
    _name: 'kaka'
}
//修改特性
Object.defineProperty(obj, "name", {
   set(){
    console.log('我被修改了')
   }
});
obj.name = 'ronaldo'

image.png

Object.defineProperty()的实际用途

vue2中的数据绑定和视图渲染就用到了这个,我们来简单模拟下吧

  • 准备一段简单的html代码
    <input class="ip" type="text">
    <div class="demo"></div>

我们要实现input输入的值同步出现在类名为demo的div中

// 模拟vue的数据驱动
let data = {
    name: 'kaka'
}

let divdom = document.querySelector('.demo')

Object.defineProperty(data,'name',{
    set(value){
        // 设置div的值为设置的值
        divdom.innerHTML = value
        return value
    }
})

// 监听并处理值
let inputdom = document.querySelector('.ip')
inputdom.oninput =  (event) => {
    let value = event.target.value
    data.name = value
}

来看下页面渲染(不会做gif图,凑合看下静态截图吧)

image.png