资讯专栏INFORMATION COLUMN

javascript 面向对象版块之对象属性

lolomaco / 3342人阅读

摘要:上一篇面向对象版块之理解对象下一篇面向对象版块之定义多个对象属性以及读取属性特性

这是 javascript 面向对象版块的第二篇文章,主要讲解的是对象的属性,首先创建一个对象:

var person = {
  name: "Nicholas",
  age: 29,
  job: "Software Engineer",
  sayName: function () {
    console.log(this.name);
  }
};

上面的例子创建了一个名为 person 的对象,并为它添加了三个属性( name 、 age 和 job )和一个方法( sayName() )。其中, sayName() 方法用于显示 this.name (将被解析为 person.name )的值。
ECMAScript 中有两种属性:数据属性和访问器属性。

数据属性

数据属性是可获取和设置值得属性,数据属性将 value 和 writable 属性包含在其描述符中。数据属性有4个描述其行为的特性:

[[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true 。

[[Enumerable]]:表示能否通过 for-in 循环返回属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true 。

[[Writable]]: 表示能否修改属性的值。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true 。

[[Value]]: 包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为 undefined 。

对于像前面例子中那样直接在对象上定义的属性,它们的 [[Configurable]] 、 [[Enumerable]]和 [[Writable]] 特性都被设置为 true ,而 [[Value]] 特性被设置为指定的值。例如:

var person = {
  name: "Nicholas",
};

这里创建了一个名为 name 的属性,为它指定的值是 "Nicholas" 。也就是说, [[Value]] 特性将被设置为 "Nicholas" ,而对这个值的任何修改都将反映在这个位置。
此时有这样一个想法,如果我不允许修改 name 属性的值,怎么办?或者说我要修改属性的默认特性,怎样才可以实现呢?要实现这些功能就要用到 Object.defineProperty()方法,这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符(descriptor)对象的属性必须是: configurable 、 enumerable 、 writable 和 value 。设置其中的一或多个值,可以修改对应的特性值。例如:

var person = {};
Object.defineProperty(person, "name", {
  writable: false,
  value: "Nicholas"
})
console.log(person.name); // Nicholas
person.name = "Greg";
console.log(person.name); // Nicholas

这个例子创建了一个 name 属性,它的值 "Nicholas" 是只读的。这个属性不可修改,如果尝试修改这个值的话在非严格模式下会被忽略,但是如果在严格模式下,会抛出错误:
Uncaught TypeError: Cannot assign to read only property "name" of object "#"
类似的规则也适用于不可配置的属性:

var person = {};
Object.defineProperty(person, "name", {
  configurable: false,
  value: "Nicholas"
})
console.log(person.name); // Nicholas
delete person.name;
console.log(person.name); // Nicholas

把 configurable 设置为 false ,表示不能从对象中删除属性。如果对这个属性调用 delete ,则在非严格模式下什么也不会发生,而在严格模式下会导致错误。而且一旦把属性定义为不可配置,就不能再把它变回可配置了。此时,再调用 Object.defineProperty() 方法修改特性,都会导致错误:

var person = {};
Object.defineProperty(person, "name", {
  configurable: false,
  value: "Nicholas"
})
console.log(person.name); // Nicholas
/* delete person.name;
console.log(person.name); // Nicholas */
Object.defineProperty(person, "name", {
  writable: true
})

也就是说 可以多次调用 Object.defineProperty() 方法修改同一属性,但是当 configurable 设置为 false 后就不可以了。

在《JavaScript 高级程序设计(第三版)》中写到:
“一旦把属性定义为不可配置的,就不能再把它变回可配置了。此时,再调用 Object.defineProperty() 方法修改除 writable 之外的特性,都会导致错误。”
但是我试了一些,即使修改的是 writable 属性,还是会报错。如果我描述的有错,还望各位大佬指出,以便交流。

在调用 Object.defineProperty() 来定义属性时。如果不指定, configurable 、 enumerable 和writable 特性的默认值都是 false。其实在日常的开发中用到这种高级方法来定义属性的机会还是比较少,不过理解这部分对理解对象还是有很大的好处。

访问器属性

访问器属性不包含数据值,但包含一对儿 getter 和 setter 函数(不过,这两个函数都不是必需的)。在读取访问器属性的时候,会调用 getter 方法,这个函数复制返回有效的值;在写入访问器属性的时候,会调用 setter 函数,这个函数复制如果修改数据。访问器属性有如下 4 个特性:

[[Configurable]] :表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。对于直接在对象上定义的属性,这个特性的默认值为true 。

[[Enumerable]] :表示能否通过 for-in 循环返回属性。对于直接在对象上定义的属性,这个特性的默认值为 true 。

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

[[Set]] :在写入属性时调用的函数。默认值为 undefined 。访问器属性不能直接定义,必须使用 Object.defineProperty() 来定义。请看下面的例子。

var book = {
  _year: 2004,
  edition: 1
}

Object.defineProperty(book, "year", {
  get: function () {
    return this._year;
  },
  set: function (newVal) {
    if (newVal > this._year) {
      this._year = newVal;
      return this.edition += newVal - 2004;
    }
  }
})
book.year = 2005;
console.log(book.edition); // 2

以上代码代码创建了一个 book 对象,定义了两个属性,_year 和 edition。而访问器属性 year 包含了一个 geter 函数和 setter 函数。getter 函数返回 _year 的值,而 setter 函数返正确的版本。当把 year 属性修改成 2005 时,而 edition 变为 2,这是使用访问器属性的常见方式,即设置一个属性的值会导致其他属性发生变化。
不一定非要同时指定 getter 和 setter,如果只指定 getter ,表明该属性不能写,只能读取,尝试写入属性会被忽略,但在严格模式下会报错。如果只指定 setter ,表明该属性不能读取,如果尝试读取,在严格模式和非严格模式下都会返回 undefined。

在《JavaScript 高级程序设计(第三版)》中写到:
“只指定 setter 函数的属性也不能读,否则在非严格模式下会返回 undefined ,而在严格模式下会抛出错误。”
但在 chrome 中测试了一下,在严格模式下不会抛出错误,返回的也是 undefined 。如果我描述的有错,还望各位大佬指出,以便交流。
小结

本片博客主要介绍了两种属性:数据属性访问器属性,介绍了这两种属性的定义以及这两种属性的特性,主要使用方法 Object.defineProperty()。其实这篇文章主要是加强对对象的理解。

上一篇:javascript 面向对象版块之理解对象

下一篇:javascript 面向对象版块之定义多个对象属性以及读取属性特性

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93176.html

相关文章

  • javascript 面向对象版块理解对象

    摘要:用代码可以这样描述安全到达国外面向过程既然说了面向对象,那么与之对应的就是面向过程。小结在这篇文章中,介绍了什么是面向对象和面向过程,以及中对象的含义。 这是 javascript 面向对象版块的第一篇文章,主要讲解对面向对象思想的一个理解。先说说什么是对象,其实这个还真的不好说。我们可以把自己当成一个对象,或者过年的时候相亲,找对象,那么你未来的老婆也是一个对象。我们就要一些属性,比...

    lovXin 评论0 收藏0
  • javascript 面向对象版块定义多个对象属性以及读取属性特性

    摘要:返回值是一个对象,如果是访问器属性,这个对象的属性有和如果是数据属性,这个对象的属性有和。上一篇面向对象版块之对象属性下一篇面向对象版块之创建对象 这是 javascript 面向对象版块的第三篇文章,主要讲解的是多个属性的定义以及读取属性的特性。前面这几章内容目的在于加深对对象的理解,这样可以利于理解后面的原型链以及继承方面的知识,或者你也可以了解一下不一样的 javascript ...

    wendux 评论0 收藏0
  • PHP面向对象编程偷懒技巧-代码重用等总结

    摘要:一个不相关的总结鄙人现在写代码容易用一句话总结根本停不下来。这种状况让人生活状态极差,黑夜白天颠倒,饱一顿饿一顿,体质下降,妹纸尽失我要远离这种状态。所以决定以后写代码尽可能只写到点,要紧的话再赶赶,一般就停下来写写总结泡泡脚蓝后碎觉。 1、OOP在粗粒度上面向对象,在细粒度上面向过程:即总体上看起来是一个模块一个模块的,细分起来还是需要一步一步执行的; 2、OOP提高了代码重用效率,...

    xiaodao 评论0 收藏0
  • 聊聊毕业设计系列 --- 项目介绍

    摘要:又将整个文艺类阅读系统的业务划分为两大部分,分别是面向管理员和合作作者的后台管理系统和面向用户的移动端,系统的需求分析将围绕这两部分进行展开。 效果展示 showImg(https://user-gold-cdn.xitu.io/2018/8/26/16576a709bd02f5f?w=1409&h=521&f=gif&s=30128195); showImg(https://user...

    Pink 评论0 收藏0
  • 聊聊毕业设计系列 --- 项目介绍

    摘要:又将整个文艺类阅读系统的业务划分为两大部分,分别是面向管理员和合作作者的后台管理系统和面向用户的移动端,系统的需求分析将围绕这两部分进行展开。 效果展示 showImg(https://user-gold-cdn.xitu.io/2018/8/26/16576a709bd02f5f?w=1409&h=521&f=gif&s=30128195); showImg(https://user...

    villainhr 评论0 收藏0

发表评论

0条评论

lolomaco

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<