getter and setter methods
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关键字的使用
下一篇:类表达式