大家好, 我是进阶学习者.
一, 前言
有两种类型的属性.
第一种是 数据属性. 已经知道如何使用它们了. 到目前为止, 使用过的所有属性都是数据属性.
第二种类型的属性是新东西. 它是 访问器属性 (accessor properties). 它们本质上是用于获取和设置值的函数, 但从外部代码来看就像常规属性.
二, Getter 和 setter
访问器属性由 "getter" 和 "setter" 方法表示. 在对象字面量中, 它们用 get 和 set 表示:
- let obj = {
- get propName() { // 当读取 obj.propName 时, getter 起作用
- }, set propName(value) {
- // 当执行 obj.propName = value 操作时, setter 起作用
- }};
当读取 obj.propName 时, getter 起作用, 当 obj.propName 被赋值时, setter 起作用.
例:
有一个具有 name 和 surname 属性的对象 user: 添加一个 fullName 属性, 该属性值应该为 "John Smith". 当然, 不想复制粘贴已有的信息, 因此可以使用访问器来实现:
- let user = {
- name: "John",
- surname: "Smith",
- get fullName() {
- return `${this.name} ${this.surname}`;
- }
- };
- alert(user.fullName); // John Smith
从外表看, 访问器属性看起来就像一个普通属性.
这就是访问器属性的设计思想. 不以函数的方式 调用 user.fullName, 正常 读取 它: getter 在幕后运行.
截至目前, fullName 只有一个 getter. 如果尝试赋值操作 user.fullName=, 将会出现错误:
- let user = {
- get fullName() {
- return `...`;
- }
- };
- user.fullName = "Test"; // Error(属性只有一个 getter)
让通过为 user.fullName 添加一个 setter 来修复它:
- let user = {
- name: "John",
- surname: "Smith",
- get fullName() {
- return `${this.name} ${this.surname}`;
- },
- set fullName(value) {
- [this.name, this.surname] = value.split(" ");
- }
- };
- // set fullName 将以给定值执行
- user.fullName = "Alice Cooper";
- alert(user.name); // Alice
- alert(user.surname); // Cooper
现在, 就有一个 "虚拟" 属性. 它是可读且可写的.
三, 访问器描述符
例:
要使用 defineProperty 创建一个 fullName 访问器, 可以使用 get 和 set 来传递描述符:
- let user = {
- name: "John",
- surname: "Smith"
- };
- Object.defineProperty(user, 'fullName', {
- get() {
- return `${this.name} ${this.surname}`;
- },
- set(value) {
- [this.name, this.surname] = value.split(" ");
- }
- });
- alert(user.fullName); // John Smith
- for(let key in user) alert(key); // name, surname
注:
一个属性要么是访问器 (具有 get/set 方法), 要么是数据属性 (具有 value), 但不能两者都是.
四, 更聪明的 getter/setter
Getter/setter 可以用作 "真实" 属性值的包装器, 以便对它们进行更多的控制.
例:
如果想禁止太短的 user 的 name, 可以创建一个 setter name, 并将值存储在一个单独的属性 _name 中:
- let user = {
- get name() {
- return this._name;
- },
- set name(value) {
- if (value.length < 4) {
- alert("Name is too short, need at least 4 characters");
- return;
- }
- this._name = value;
- }
- };
- user.name = "Pete";
- alert(user.name); // Pete
- user.name = ""; // Name 太短了......
注:
从技术上讲, 外部代码可以使用 user._name 直接访问 name. 但是, 这儿有一个众所周知的约定, 即以下划线 " 开头的属性是内部属性, 不应该从对象外部进行访问.
五, 兼容性
访问器的一大用途是, 它们允许随时通过使用 getter 和 setter 替换 "正常的" 数据属性, 来控制和调整这些属性的行为.
开始使用数据属性 name 和 age 来实现 user 对象:
- function User(name, age) {
- this.name = name;
- this.age = age;
- }
- let john = new User("John", 25);
- alert( john.age ); // 25
但情况可能会发生变化.
可能会决定存储 birthday, 而不是 age, 因为它更精确, 更方便:
现在应该如何处理仍使用 age 属性的旧代码呢?
可以尝试找到所有这些地方并修改它们, 但这会花费很多时间, 而且如果其他很多人都在使用该代码, 那么可能很难完成所有修改.
为 age 添加一个 getter 来解决这个问题:
- function User(name, birthday) {
- this.name = name;
- this.birthday = birthday;
- // 年龄是根据当前日期和生日计算得出的
- Object.defineProperty(this, "age", {
- get() {
- let todayYear = new Date().getFullYear();
- return todayYear - this.birthday.getFullYear();
- }
- });
- }
- let john = new User("John", new Date(1992, 6, 1));
- alert(john.birthday); // birthday 是可访问的
- alert(john.age); // ......age 也是可访问的
现在旧的代码也可以工作, 而且还拥有了一个不错的附加属性.
六, 总结
本文基于 JavaScript 基础, 介绍了 getter 和 setter 函数的使用. 对于其中的属性, 通过案例的样式, 运行效果图的展示, 进行详细的讲解. 同时拓展相对于的内容, 希望能够帮助你更好的理解.
欢迎大家积极尝试, 有时候看到别人实现起来很简单, 但是到自己动手实现的时候, 总会有各种各样的问题, 切勿眼高手低, 勤动手, 才可以理解的更加深刻.
代码很简单, 希望对你学习有帮助.
来源: http://developer.51cto.com/art/202108/679994.htm