详细讲解Object.defineProperty() 并实现双向绑定

文章发布于 2023-07-14

Object.defineProperty() 方法是在指定对象上添加一个新属性,或者修改对象上的一个现有属性,然后返回该对象。

语法

Object.defineProperty(obj, prop, descriptor)
  • obj 目标对象
  • prop 目标对象的属性
  • prop属性的特性参数

兼容性

在ie8只能在DOM对象上使用,如果在原生的对象使用 Object.defineProperty()会报错。

对象属性特性描述参数descriptor

我这里就叫属性特性描述参数吧,那我为什么会叫属性特性描述参数呢?比如说在descriptor 里面可以设置属性的读写删除权限,以及是否可以被枚举。有了这些权限,那么对这个属性就更好控制了。

名称 说明 返回类型 默认值
value 属性对应的值,可以使任意类型的值 undefined undefined
writable 属性的值是否可以被重写 boolean false
enumerable 是否可以被枚举(使用for...in或Object.keys()) boolean false
configurable 是否可以删除目标属性或是否可以再次修改属性的特性(writable, configurable, enumerable) boolean false
get getter 获得属性值的方法 function
set setter 设置属性值的方法 function

添加特性描述

对象属性添加特性描述,提供两种形式来添加:

  • 数据描述
  • 存取器描述
数据描述

直接给属性添加对应的权限。比如下面的例子中,给objmsg属性添加可枚举、可重写、可读、不可删除的权限。

var obj  = {
    msg:'hello'
}

Object.defineProperty(obj,"msg",{
    configurable:false,
    enumerable:true
    value:'hello world',
    writable:true
});

存取器描述

使用存取器描述属性特性的时候 ,没有valuewritable。取而代之的是 setget

var obj = {};
Object.defineProperty(obj,"msg",{
    get:function (){},
    set:function (value){}
    configurable: false
    enumerable: true
});

实例

利用Object.defineProperty()方法来实现双向绑定。vue2也是使用Object.defineProperty()来实现的额。下面是双向绑定的完整实例:

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>

<div id="app"></div>
<input type="" value="" id="input">
<script type="text/javascript">
    var obj = {}
    function watch(obj ,name ,callback){
        Object.defineProperty(obj,name,{
            set(newValue){
                value = newValue
                callback(newValue)
            },
            get(value){
                return value
            }
        })
    }

    function dosome(val){
        app.innerHTML = val
        input.value = val
    }

    var input = document.getElementById('input'),app = document.getElementById('app')
    input.oninput=function(e){
        var value = e.target.value
        obj['msg'] = value
    }

    watch(obj ,'msg' ,dosome)
</script>
</body>
</html>