阿里云主机折上折
  • 微信号
Current Site:Index > getter and setter methods

getter and setter methods

Author:Chuan Chen 阅读数:58865人阅读 分类: JavaScript

Basic Concepts of ECMAScript 6 Getter and Setter Methods

ECMAScript 6 introduced a more concise syntax for defining getter and setter methods in objects. These methods allow custom logic to be executed when accessing or modifying object properties. The getter method is called when reading a property, and the setter method is called when setting a property.

const obj = {
  _value: 0,
  get value() {
    console.log('Getting value');
    return this._value;
  },
  set value(newValue) {
    console.log('Setting value');
    this._value = newValue;
  }
};

obj.value = 42; // Outputs "Setting value"
console.log(obj.value); // Outputs "Getting value" followed by 42

Getter and Setter Methods in Classes

In ES6 classes, getter and setter methods can be defined more clearly. They appear as regular methods but are prefixed with the get and set keywords.

class Temperature {
  constructor(celsius) {
    this._celsius = celsius;
  }

  get celsius() {
    return this._celsius;
  }

  set celsius(value) {
    if (value < -273.15) {
      throw new Error('Temperature below absolute zero');
    }
    this._celsius = value;
  }

  get fahrenheit() {
    return this._celsius * 9/5 + 32;
  }

  set fahrenheit(value) {
    this._celsius = (value - 32) * 5/9;
  }
}

const temp = new Temperature(25);
console.log(temp.fahrenheit); // 77
temp.fahrenheit = 100;
console.log(temp.celsius); // 37.777...

Combining Computed Property Names with Getters/Setters

ES6 allows computed property names to be combined with getter and setter methods, which is particularly useful when property names need to be determined dynamically.

const prefix = 'user_';

const user = {
  _name: 'John',
  _age: 30,

  get [prefix + 'name']() {
    return this._name;
  },

  set [prefix + 'name'](value) {
    if (value.length < 2) {
      throw new Error('Name too short');
    }
    this._name = value;
  },

  get [prefix + 'age']() {
    return this._age;
  },

  set [prefix + 'age'](value) {
    if (value < 0) {
      throw new Error('Age cannot be negative');
    }
    this._age = value;
  }
};

console.log(user['user_name']); // "John"
user['user_name'] = 'Alice';
console.log(user['user_name']); // "Alice"

Defining Getters/Setters with Object.defineProperty

Although ES6 provides a more concise syntax, the Object.defineProperty method is still available, especially when finer control over property descriptors is needed.

const circle = {
  _radius: 1
};

Object.defineProperty(circle, 'radius', {
  get() {
    return this._radius;
  },
  set(value) {
    if (value <= 0) {
      throw new Error('Radius must be positive');
    }
    this._radius = value;
  },
  enumerable: true,
  configurable: true
});

Object.defineProperty(circle, 'area', {
  get() {
    return Math.PI * this._radius ** 2;
  },
  enumerable: true,
  configurable: true
});

console.log(circle.radius); // 1
circle.radius = 2;
console.log(circle.area); // ≈12.566

Getters/Setters and Prototypal Inheritance

Getter and setter methods exhibit special behavior in prototypal inheritance because they are dynamically computed when properties are accessed.

class Shape {
  constructor() {
    this._color = 'black';
  }

  get color() {
    return this._color;
  }

  set color(value) {
    this._color = value;
  }
}

class Circle extends Shape {
  constructor(radius) {
    super();
    this._radius = radius;
  }

  get area() {
    return Math.PI * this._radius ** 2;
  }
}

const myCircle = new Circle(5);
console.log(myCircle.color); // "black"
myCircle.color = 'red';
console.log(myCircle.color); // "red"
console.log(myCircle.area); // ≈78.5398

Combining Getters/Setters with Proxy Objects

ES6's Proxy object can be combined with getter/setter methods to implement advanced property access control.

const target = {
  _secret: 'confidential',
  get secret() {
    return this._secret;
  },
  set secret(value) {
    this._secret = value;
  }
};

const handler = {
  get(target, prop) {
    if (prop === 'secret') {
      return 'ACCESS DENIED';
    }
    return target[prop];
  },
  set(target, prop, value) {
    if (prop === 'secret') {
      throw new Error('Cannot modify secret property');
    }
    target[prop] = value;
    return true;
  }
};

const proxy = new Proxy(target, handler);

console.log(proxy.secret); // "ACCESS DENIED"
console.log(target.secret); // "confidential"
try {
  proxy.secret = 'new value'; // Throws an error
} catch (e) {
  console.error(e.message); // "Cannot modify secret property"
}

Practical Use Cases for Getters/Setters

Getter and setter methods have various applications in real-world development, including data validation, computed properties, access control, and logging.

class User {
  constructor(firstName, lastName) {
    this._firstName = firstName;
    this._lastName = lastName;
    this._loginAttempts = 0;
    this._lastLogin = null;
  }

  get fullName() {
    return `${this._firstName} ${this._lastName}`;
  }

  set fullName(value) {
    const parts = value.split(' ');
    if (parts.length !== 2) {
      throw new Error('Full name must be "firstName lastName"');
    }
    this._firstName = parts[0];
    this._lastName = parts[1];
  }

  get loginAttempts() {
    return this._loginAttempts;
  }

  get lastLogin() {
    return this._lastLogin || 'Never logged in';
  }

  login() {
    this._loginAttempts++;
    this._lastLogin = new Date();
    console.log(`${this.fullName} logged in at ${this._lastLogin}`);
  }
}

const user = new User('John', 'Doe');
console.log(user.fullName); // "John Doe"
user.fullName = 'Jane Smith';
console.log(user.fullName); // "Jane Smith"
user.login(); // "Jane Smith logged in at [current date]"
console.log(user.loginAttempts); // 1
console.log(user.lastLogin); // [current date]

Performance Considerations for Getters/Setters

While getter and setter methods provide flexibility, their overhead should be considered in performance-sensitive scenarios.

class Vector {
  constructor(x, y) {
    this._x = x;
    this._y = y;
    this._length = Math.sqrt(x * x + y * y);
  }

  get x() {
    return this._x;
  }

  set x(value) {
    this._x = value;
    this._updateLength();
  }

  get y() {
    return this._y;
  }

  set y(value) {
    this._y = value;
    this._updateLength();
  }

  get length() {
    return this._length;
  }

  _updateLength() {
    this._length = Math.sqrt(this._x * this._x + this._y * this._y);
  }
}

const vec = new Vector(3, 4);
console.log(vec.length); // 5
vec.x = 6;
console.log(vec.length); // ≈7.211

Getters/Setters and JSON Serialization

When an object contains getter methods, the behavior of JSON.stringify should be noted, as only data properties are serialized by default.

const person = {
  _firstName: 'John',
  _lastName: 'Doe',
  get fullName() {
    return `${this._firstName} ${this._lastName}`;
  },
  toJSON() {
    return {
      firstName: this._firstName,
      lastName: this._lastName,
      fullName: this.fullName
    };
  }
};

console.log(JSON.stringify(person));
// Output: {"firstName":"John","lastName":"Doe","fullName":"John Doe"}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:super关键字的使用

下一篇:类表达式

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.