学习JS的数据属性和访问器属性

ECMAScript中有两类属性,分别是数据属性与访问器属性。

1.1 数据属性

数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有 4 个描述其行为的 特性。

  • [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。

  • [[Enumerable]]:表示能否通过for-in循环返回属性。

  • [[Writable]]:表示能否修改属性的值。

  • [[Value]]:包含这个属性的数据值。

通过new object或者对象字面量方式创建对象定义的属性,他们的[[Configurable]][[Enumerable]][[Writable]]特征均为true,而[[Value]]值被设置为指定的值。

举例

//对象字面量
var cat = {
    name: "TOM",
    age:"2"
}
console.log(Object.getOwnPropertyDescriptor(cat,"name"))
//输出结果:{ value: 'TOM', writable: true, enumerable: true, configurable: true }
//getOwnPropertyDescriptor可以获取指定属性的描述
Object.defineProperty(cat,"name",{writable:false})
console.log("修改前",cat.name)
cat.name= "panghu"
console.log("修改后",cat.name)
//修改前 TOM
//修改后 TOM

使用Object.defineProperty()可以修改默认属性。包含三个参数:属性所在对象,属性名称,描述符对象。

Object.defineProperty(cat,"name",{writable:false})

以上代码将name属性的[[writable]]特性值设为false,表示该属性只可读不可修改。如果修改name的值,非严格模式下,赋值操作会被忽略,在严格模式下,会抛出错误。

1.2 访问器属性

访问器属性有如下 4 个特性。

  • [[Configurable]]:特性同1.1数据属性的该特征值

  • [[Enumerable]]:特性同1.1数据属性的该特征值

  • [[Get]]:在读取属性时调用的函数。默认值为 undefined。

  • [[Set]]:在写入属性时调用的函数。默认值为 undefined。

访问器属性不能直接定义,必须使用 Object.defineProperty()来定义

var dog = {
    _age: "2",
    edition:1
}
Object.defineProperty(dog,"age",{
    get:function(){
        return this._age
    },
    set:function(newAge){
        this._age = newAge
        this.edition+=1
    }
})
console.log(dog.age) //2
dog.age=3
console.log("age:"+dog.age+" editor:"+dog.edition)//age:3 editor:2
console.log(Object.getOwnPropertyDescriptor(dog,"age"))
//{
  //get: [Function: get],
  //set: [Function: set],
  //enumerable: false,    属性默认不可枚举
  //configurable: false   描述符默认不可修改,属性不可删除
//}

以上代码定义了_ageedition两个数据属性,同时定义了age这个访问器属性。age访问器属性包含getset两个方法,get方法返回_age属性的值,set方法通过计算来确定正确的版本。

数据属性和访问器属性共享configurableenumerable(默认值是指在使用 Object.defineProperty() 定义属性时的默认值):

  • configurable

    当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。 默认为 false

  • enumerable

    当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。 默认为 false

1.3 访问器属性实现双向绑定

了解了这些基本概念,不禁有一个疑问,访问器属性有什么作用?

访问器属性使用的常见方式,即设置一个值会导致其他属性发生变化,该思想是vue双向绑定数据实现的核心内涵。

下面通过一个实例了解一下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <input id="input"/></br>  //input输入框
        <script>
            let inputNode = document.getElementById('input');
            let person = {}
            Object.defineProperty(person, 'name' ,{  //为person.name定义访问器属性的内容
                configurable: true,
                get: function () {
                    console.log('person.name.get():'+ inputNode.value)
                    return inputNode.value
                },
                set: function (newValue) {
                    console.log('person.name.set():' + newValue)
                    inputNode.value = newValue
                }
            })
            inputNode.oninput = function () { 
                //为input输入框添加监听方法,input输入值发生改变时,将输入值赋值给person.name
                console.log('inputNode.oninput: ' + inputNode.value)
                person.name = inputNode.value;  //将input输入框的数据与perosn对象的name属性值绑定
                console.log('person.name: '+ person.name)
            }
        </script>
    </body>
</html>

在输入框中输入232

输出:

10:25:06.509 inputNode.oninput: 2 at study_property.html:24
10:25:06.522 person.name.set():2 at study_property.html:19
10:25:06.524 person.name.get():2 at study_property.html:15
10:25:06.531 person.name: 2 at study_property.html:26
10:25:07.111 inputNode.oninput: 23 at study_property.html:24
10:25:07.122 person.name.set():23 at study_property.html:19
10:25:07.123 person.name.get():23 at study_property.html:15
10:25:07.133 person.name: 23 at study_property.html:26
10:25:09.035 inputNode.oninput: 232 at study_property.html:24
10:25:09.051 person.name.set():232 at study_property.html:19
10:25:09.052 person.name.get():232 at study_property.html:15
10:25:09.067 person.name: 232 at study_property.html:26

以上代码实现了一个将input输入框的数据与perosn对象的name属性值绑定的实例,input输入框内的数据发生改变会同步影响perosn.name的值,而对perosn.name的任何修改也会同步到input输入框内

2.1 Writable 属性

writable 属性设置为 false 时,该属性被称为“不可写的”。它不能被重新赋值。

var o = {}; // 创建一个新对象
​
Object.defineProperty(o, 'a', {
  value: 37,
  writable: false
});
​
console.log(o.a); // 37
o.a = 25; // No error thrown
// (it would throw in strict mode,
// even if the value had been the same)非严格模式下不会报错
console.log(o.a); //  37 对象的a属性的值不能被修改,因为属性Writable为false
//strict mode 严格模式
(function() {
  'use strict';
  var o = {};
  Object.defineProperty(o, 'b', {
    value: 2,
    writable: false
  });
  o.b = 3; // throws TypeError: "b" is read-only 报错b属性只读,不能修改
  return o.b; // returns 2 without the line above
}());

2.2 enumerable属性

enumerable 定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。

var o = {};
Object.defineProperty(o, "a", { value : 1, enumerable: true });
Object.defineProperty(o, "b", { value : 2, enumerable: false });
Object.defineProperty(o, "c", { value : 3 }); // enumerable 默认为 false
o.d = 4; // 如果使用直接赋值的方式创建对象的属性,则 enumerable 为 true
​
​
for (var i in o) {
  console.log(i);
}
// a d
// b c 不可以被枚举
​
console.log(Object.keys(o)); // ['a', 'd'] // b c 不可以被枚举
​
console.log(o.propertyIsEnumerable('a')); // true
console.log(o.propertyIsEnumerable('b')); // false
console.log(o.propertyIsEnumerable('c')); // false
console.log(o.propertyIsEnumerable('d')); // true

2.3 Configurable 属性

configurable 特性表示对象的属性是否可以被删除,以及除 valuewritable 特性外的其他特性是否可以被修改。

var o = {};
Object.defineProperty(o, 'a', {
  value:1,
  configurable: false
});
console.log('o.a: ',o.a) // o.a:  1
delete o.a
console.log('o.a: ',o.a) // o.a:  1

[[Configurable]]特性设置为false后,属性不能从对象中删除,此时调用delete在非严格模式下什么也不会发生,在严格模式下会抛出错误。

var o = {};
Object.defineProperty(o, 'a', {
  value:1,
  configurable: false
});
​
Object.defineProperty(o, 'a', {
  value:1,
  writable: false,
  enumerable:false
});
console.log(Object.getOwnPropertyDescriptor(o,"a"))
//输出{ value: 1, writable: false, enumerable: false, configurable: false }
var o = {};
Object.defineProperty(o, 'a', {
  value:1,
  writable: false,
  enumerable:false,
  configurable:false
});
Object.defineProperty(o, 'a', {
  writable: true,
  enumerable:true,
});
console.log(Object.getOwnPropertyDescriptor(o,"a")) //TypeError: Cannot redefine property: a
​

[[Configurable]]特性设置为false后,如果[[Writable]][[enumerable]]以前为true,则还可以将其修改为false,如果[[Writable]][[enumerable]]以前为false,则不可修改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值