博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript对象的数据属性与访问器属性
阅读量:6910 次
发布时间:2019-06-27

本文共 6533 字,大约阅读时间需要 21 分钟。

首先介绍了JavaScript对象数据属性与访问器属性的相关概念,然后介绍了属性定义与读取的相关方法,最后对JavaScript对象数据属性与访问器属性的知识做了一些扩展,并手动实现了一个简单的数据双向绑定实例。

文中如果有疏漏错误之处,各位小伙伴可在文末评论中提出,fanweiren一定及时修正,以避免误导。另外,如果对本文有不理解的地方,也欢迎评论提出,fanweiren一定积极为大家解答。

一. 创建JavaScript对象

创建JavaScript对简单的方法有两种:一是直接创建一个object实例,然后为他添加属性与方法,二是通过对象字面量语法的方式创建。

1.1 new object

var person = new Object();person.name = "Nicholas";person.age = 29;person.job = "Software Engineer";person.sayName = function(){    alert(this.name);};复制代码

上述实例创建了一个名为person的实例对象,并为其添加了三个属性(nameagejob)和一个方法(sayName)。

1.2 对象字面量

上述示例同样可通过对象字面量的语法实现如下。

var person = {    name: "Nicholas",    age: 29,    job: "Software Engineer",    sayName: function() {        alert(this.name);    }};复制代码

二. 属性类型

对于1.11.2的创建的每个实例都有自己的属性和方法,这些属性在创建时都带有一些特征值,这些特征值仅供内部使用,在JavaScript中不能直接访问他们,按规定这些特征值需要放在两对方括号中,例如[[Enumerable]]

ECMAScript中有两类属性,分别是数据属性选择器属性

1.1 数据属性

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

  • [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。
  • [[Enumerable]]:表示能否通过for-in循环返回属性。
  • [[Writable]]:表示能否修改属性的值。
  • [[Value]]:包含这个属性的数据值。

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

var person = {    name: "Nicholas"}复制代码

以上代码通过对象字面量的方式定义了一个person对象,并为它指定了name属性,此时name属性的四个特征值,[[Configurable]][[Enumerable]][[Writable]]特征均为true,而[[Value]]Nicholas

要修改属性默认的特性,必须使用Object.defineProperty()方法,可同时修改一个或多个特性值,该方法接收三个参数:

  • object:属性所在的对象
  • propertyName:属性的名字
  • descripor:属性的描述符,必须是[[Configurable]][[Enumerable]][[Writable]][[Value]]中的一个或者多个值。
var person = {    name: fanweiren}; Object.defineProperty(person, "name", {  writable: false,  value: "Nicholas" }); alert(person.name); //"Nicholas" person.name = "Greg"; alert(person.name); //"Nicholas"复制代码

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

var person = {    name: fanweiren}; Object.defineProperty(person, "name", {  configurable: false,  value: "Nicholas" }); alert(person.name); //"Nicholas" delete person.name; alert(person.name); //"Nicholas"复制代码

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

一旦把[[Configurable]]特性设置为false即不可配置后,就不能在变回可配置了。且设置为false后,[[Enumerable]][[Writable]]也都不能修改了。

发现一个奇怪的现象,[[Configurable]]特性设置为false后,如果[[Writable]]以前为true,则还可以将其修改为false,如果[[Writable]]以前为false,则不可修改。

1.2 访问器属性

访问器属性不包含数据值;它们包含一对儿gettersetter 函数(不过,这两个函数都不是必需的)。在读取访问器属性时,会调用getter 函数,这个函数负责返回有效的值;在写入访问器属性时,会调用 setter函数并传入新值,这个函数负责决定如何处理数据。访问器属性有如下 4 个特性。

  • [[Configurable]]:特性同1.1数据属性的该特征值
  • [[Enumerable]]:特性同1.1数据属性的该特征值
  • [[Get]]:在读取属性时调用的函数。默认值为 undefined。
  • [[Set]]:在写入属性时调用的函数。默认值为 undefined。

访问器属性不能直接定义,必须使用 Object.defineProperty()来定义。请看下面的例子。

var book = {  hideYear: 2004,  edition: 1 }; Object.defineProperty(book, "year", {  get: function(){  return this.hideYear;  },  set: function(newValue){  if (newValue > 2004) {  this.hideYear = newValue;  this.edition += newValue - 2004;  }  } }); book.year = 2005; alert(book.edition); //2复制代码

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

get和set可以不同时使用,但在严格模式下只其中一个,会抛出错误

三点总结:

  1. 所有直接通过new object或者对象字面量为对象添加的属性均为数据属性,访问器属性必须用Object.defineProperty()定义。
  2. 通过new object或者对象字面量为对象添加的属性,其[[Configurable]][[Enumerable]][[Writable]]属性默认均为true,通过Object.defineProperty()定义的属性,对于defineProperty方法没定义的特征,默认为false
// 通过`new object`或者对象字面量为对象添加的属性var person = {    name: 'fanweiren'} // configurable、enumerable、writable均为true// 通过`Object.defineProperty()`定义的属性Object.defineProperty(book, "name", {    value: 'fanweiren'} // configurable、enumerable、writable均为falseObject.defineProperty(book, "name", {    configurable: true    value: 'fanweiren'}// configurable为true,enumerable、writable为false复制代码
  1. 一个属性要么为数据属性,要么为访问器属性,不可能既是数据属性又是访问器属性,即数据描述符与存取描述符不可混用,会抛出错误。
var obj = {};Object.defineProperty(obj, 'a', {    value: 'a1',    get: function() {       return 'a2'    } // 错误!数据描述符与存取描述符不可混用});复制代码
  1. 访问器属性使用的常见方式,即设置一个值会导致其他属性发生变化,该思想是vue双向绑定数据实现的核心内涵。

三. 定义多个属性

利用Object.defineProperty()定义单个属性。利用Object.defineProperties()同时定义多个属性,该方法接收两个参数,具体使用方式见如下代码。

var book = {}; Object.defineProperties(book, {  _year: {     value: 2004  },  edition: {     value: 1  },  year: {      get: function(){        return this._year;      },      set: function(newValue){         if (newValue > 2004) {              this._year = newValue;              this.edition += newValue - 2004;         }     }  } });复制代码

以上代码为对象book定义了三个属性,其中_yearedition为数据属性,year为访问器属性。

四. 读取数据的属性

Object.getOwnPropertyDescriptor()方法可以取得给定属性的描述符。这个方法返回值是一个对象,如果是访问器属性,这个对象的属性有configurableenumerablegetset;如果是数据属性,这 个对象的属性有configurableenumerablewritablevalue。对于第三部分(定义多个属性)的代码,调用Object.getOwnPropertyDescriptor()方法后结果如下:

var descriptor = Object.getOwnPropertyDescriptor(book, "_year");console.log(JSON.stringify(descriptor))//{"value":2004,"writable":false,"enumerable":false,"configurable":false}alert(typeof descriptor.get);     //"undefined"var descriptor = Object.getOwnPropertyDescriptor(book, "year");console.log(JSON.stringify(descriptor)) // {"enumerable":false,"configurable":false}alert(typeof descriptor.get); // functionalert(typeof descriptor.set); // function复制代码

五 相关扩展

5.1 全局环境中的赋值导致configurable默认为false

全局环境下,a=1中的a相当于window的一个属性,而var a=1中的a相当于定义的一个变量。

a = 1; //a是其所在对象的一个属性, configurable与对象字面量定义属性一样,默认为true复制代码
var a = 1; // 通过var或let初始化的,configurable属性默认为false复制代码

5.2. 利用访问器属性实现简单的数据双向绑定

    
Title
复制代码

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

注意是将inputperosn.name数据绑定,而不是inputbutton绑定,button的作用仅仅是改变perosn.name的值,方便演示而已。 具体步骤为

  1. 首先写一个简单HTML页面,包括一个input输入框与一个button按钮
  2. perosn.name定义访问器属性的特性,重写setget方法,set方法会获取input输入框的值并返回,而set方法会为input输入框重新赋值。当perosn.name被赋值时,input输入框的值会同步变化。
  3. input输入框添加监听方法,input输入值发生改变时会被触发,触发此方法时input内的值会被赋值给perosn.name,导致perosn.name同步变化。
  4. btn按钮添加点击的监听方法,主要是为了方便为perosn.name赋值,以观察第3步所说的现象。如果要观察第2步的现象,可以按F12观察console页面的打印数据。

下图为上述代码的示意图。

六. 总结

本文从对象的创建引出对象数据属性与访问器属性的概念,首先介绍了数据属性与访问器属性的相关知识,然后介绍了属性定义与读取的相关方法。主要结论如下:

  1. javascript对象的属性分为数据属性与访问器属性两类,通过new object与对象字面量定义的属性都为数据属性,访问器属性必须通过Object.defineProperty()方法定义。
  2. 通过new object或者对象字面量为对象添加的属性,其[[Configurable]][[Enumerable]][[Writable]]属性默认均为true,通过Object.defineProperty()定义的属性,对于defineProperty方法没定义的特征,默认为false
  3. 一个属性要么为数据属性,要么为访问器属性,不可能既是数据属性又是访问器属性。
  4. 访问器属性使用的常见方式,即设置一个值会导致其他属性发生变化,该思想是vue双向绑定数据实现的核心内涵。
  5. [[Configurable]]表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,[[Enumerable]]表示能否通过for-in循环返回属性。

转载于:https://juejin.im/post/5cbac7fff265da0378759399

你可能感兴趣的文章
oc面向对象特性: 多态
查看>>
java--xml文件读取(DOM)
查看>>
Bootstrap-表单
查看>>
hiveserver2连接报错: User: root is not allowed to impersonate anonymous (state=08S01,code=0)
查看>>
android:使用Messenger进行进程间通信(一)
查看>>
HDU(1016),打素数环
查看>>
2007 Asia - Nanjing F题,字典树
查看>>
Gym 100090D Insomnia
查看>>
完全隐藏Master Page左边导航条只有管理员才可以看见
查看>>
微信支付详解
查看>>
ubuntu install GTK-GNOME development environment
查看>>
为iDempiere 1.0b安装中文语言包(基于Ubuntu Desktop 12.04 LTS)
查看>>
Graphviz样例之UML图
查看>>
XmlBeanFactory
查看>>
LVM逻辑卷
查看>>
TCP服务器和客户端最大连接数
查看>>
手机端扫描证件识别SDK
查看>>
springboot shiro配置
查看>>
ZetCode PyQt4 tutorial basic painting
查看>>
WPF RichTextBox的Document属性的序列化与反序列化
查看>>