数据属性和访问器属性

241 阅读4分钟

在ECMAScript中属性按类型可分为两种:数据属性和访问器属性。

一.数据属性

数据属性有4个特性(属性描述符):
configurable :    表示是否能通过delete删除,能否修改属性的特性,以及能否将 数据属性修                            改为访问器属性
enumerable :  表示能否通过for- in循环返回属性
writable :           表示能否改变属性的值
value :               属性对应的值

注意点:
通过字面量或者构造函数实例创建的对象,其属性都是数据属性且各个描述符默认是true(除value)

1.1 Object.getOwnPropertyDescriptor()方法

返回指定对象上一个自有属性对应的属性描述符对象。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

参数(2个):

obj:属性所在的对象

prop: 属性名
返回值: 如果指定的属性存在于对象上,则返回其属性描述符对象(propertydescriptor),                否则返回undefined

图一:使用getOwnPropertyDescriptor方法观察属性描述符


图二:数据属性描述符的作用


图二是当数据属性的各个描述符为true时的功能测试,也可以用defineproperty方法修改为false进行测试

1.2 Object.defineProperty()方法

用于直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

参数(3个):

obj:目标对象

prop:要添加的新属性或要修改的属性
descriptor:将要被定义或被修改的属性描述符对象


关于使用defineProperty需要注意的有:
一.当configurable设置为false后,不可再修改回ture,否则报错
二.使用defineProperty定义的属性,对于没有设置的特性,默认为false或undefined(如果value没有设置值)
三.当只设置configurable,并且为false时,value,enumerable,writable之后这4个特性都
不 可修改,否则报错
四.当configurable为false时,其他特性也有设置时:如图三所注

var obj = {}
Object.defineProperty(obj,'name',{// value:'Macky', //之前若设置writable为true,修改value的值不报错。否则报错configurable:false,// enumerable:true, //不管之前enumerable是true或者false,之后修改都会报错// writable:true, //之前若设置writable为false,之后则不可以修改,若之前为true,则可以改为false})
var des = Object.getOwnPropertyDescriptor(obj,'name');console.log(des);

图三:


二.访问器属性

访问器属性也有4个特性(属性描述符):

configurable:
enumerable:
(以上两个与数据属性里的作用一致)
get: 目标属性被访问就会调回此方法,并将此方法的运算结果返回用户
set: 一旦目标属性被赋值,就会调回此方法

注意点:
1.访问器属性只能通过defineProperty方法创建
2.一个属性只可能是数据属性或者访问器属性,如果该属性同时拥有(value或writable)和(set或get),则会出现异常


三.通过访问器属性实现简单的双向数据绑定

模拟最近餐饮店比较火的10秒免单的小游戏,同时来解释一个简单的双向绑定,代码如下: 

<!DOCTYPE html><html lang="en">
<head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <meta http-equiv="X-UA-Compatible" content="ie=edge">    <title>Document</title>    <style>        * {            padding: 0;            margin: 0;        }
        #goBtn,        #stopBtn,        #resetBtn {            width: 40px;            height: 40px;            border-radius: 20px;            background-color: green;            margin-left: 4px;            font-size: 8px;            text-align: center;        }
        #stopBtn {            background-color: red;        }
        #resetBtn {            background-color: yellow;        }
        #luckyInput {            width: 150px;            height: 15px;            text-align: center;        }    </style></head>
<body>    <input type="text" placeholder="10.00免单" id='luckyInput'><br>    <button id='goBtn'>Go</button>    <button id='stopBtn'>Stop</button>    <button id='resetBtn'>Reset</button>    <script>        var luckyInput = document.getElementById('luckyInput');        var goBtn = document.getElementById('goBtn');        var stopBtn = document.getElementById('stopBtn');        var resetBtn = document.getElementById('resetBtn');        var luckyNumber = {};        Object.defineProperty(luckyNumber, 'num', {            get: function () {                return luckyInput.value;
            },            set: function (newNum) {                luckyInput.value = newNum; //将            }        });        var m = 0, ms = 0;        var t = 0;        var timeStart;        function setTime(v) {            if (v.toString().length <= 1) return '0' + v;            return v;        }        //计时器代码        function game() {            m = setTime(Math.floor(t / 100 % 11));             ms = setTime(Math.floor(t % 100));             luckyNumber.num = m + ":" + ms; //给num赋值会调用set函数,同时输入框内的值也会获取到该值            t = t + 1;            timeStart = setTimeout("game()", 10);        }        //点击开始          var onOroff = true        goBtn.onclick = function (contr) {          game();        }        //点击停止        stopBtn.onclick = function () {            clearTimeout(timeStart)        }        //点击重置        resetBtn.onclick = function () {            clearTimeout(timeStart)            luckyInput.value = '10.00免单'            // console.log('此时num的值:'+luckyNumber.num)        }        //直接在输入框中输入值时,该值最终也会通过get函数获取到        luckyInput.oninput = function () {            luckyNumber.num = luckyInput.value;            // console.log('在输入框内直接输入时,luckyNumber.num的值:' + luckyNumber.num)        }    </script></body></html>

 

以上双向绑定的核心内容在于,当点击开始按钮时,会执行game函数,这里通过给num赋值(改变num的值),会调用set,将新值赋值给输入框内的值,同时利用oninput事件监听输入框写入的值,将这个值赋值给num。这样就实现了一个简单的num与luckyInput.value数据的双向绑定。另外,get在对象的属性被访问时会调用,因此通过luckyInput.num可同时查看输入框内的值和属性num的值。