对象属性的get和set详解
你可能见过类似下面的代码:
const r = {
get value() {
return value
},
set value(newValue) {
if (newValue !== this.value) {
this.value = newValue
}
}
}
这里的get和set写法是什么意思?为啥对象属性可以这样设置,不应该是xx:xxx
的写法吗?
在传统的javaScript
中,对象属性可以通过两种方式设置:
- 点表示法:
objectName.propertyName
- 方括号表示法:
objectName['propertyName']
但有时需要允许访问返回动态计算值的属性,或者需要反映内部变量的状态,而不需要使用显式方法调用。因而在ES5
引入了get
和 set
,允许开发者定义getter
和 setter
方法,以便更灵活地控制属性的访问和赋值过程。
get(getter)
get
语法将对象属性绑定到查询该属性时将被调用的函数,简称获取对象属性的时候调用绑定的函数。
语法
创建
{get prop() { ... } }
{get [expression]() { ... } }
参数说明:
prop
: 要绑定到给定函数的属性名,即对哪个属性名进行监听expression
: 使用一个计算属性名的表达式绑定到给定的函数。
注意事项:
-
必须不带参数
-
它不能与另一个
get
或具有相同属性的数据条目同时出现在一个对象字面量中(不允许使用{ get x() { }, get x() { } }
和{ x: ..., get x() { } }
)。
删除
删除使用delete
,就可删除getter
实例
// {get prop() { ... } }
const obj = {
log: ["example", "test"],
get latest() {
if (this.log.length == 0) return undefined;
return this.log[this.log.length - 1];
},
};
console.log(obj.latest); // "test".
// {get [expression]() { ... } } 使用计算出的属性名
var expr = "foo";
var obj = {
get [expr]() {
return "bar";
},
};
console.log(obj.foo); // "bar"
// 删除
delete obj.latest;
get VS defineProperty
当使用 get
关键字时,它和Object.defineProperty()
有类似的效果。而在类中使用时,get
会将**getter
** 方法定义在类的原型上;Object.defineProperty()
可以选择将属性定义在对象的实例上,也可以将其定义在原型上。
在类中使用 get
关键字的效果类似于在类的原型上使用 Object.defineProperty()
来定义属性的 getter 方法,而不是直接定义属性。
这意味着当你创建类的实例时,这个 getter 方法将在实例的原型链上被继承,而不是在实例本身上。
class Example {
get hello() {
return "world";
}
}
const obj = new Example();
const obj2 = new Example();
// get 关键字定义在类的原型上,因此所有 MyClass 的实例都共享相同的 getter 方法。
console.log(obj.hello);// "world"
console.log(obj2.hello); // "world"
console.log(Object.getOwnPropertyDescriptor(obj, "hello")); // undefined
Object.getOwnPropertyDescriptor()
:静态方法返回一个对象,该对象描述给定对象上特定属性(即直接存在于对象上而不在对象的原型链中的属性)的配置。
// 使用 Object.defineProperty() 定义属性
// 未指定 obj 的原型,因此该属性只存在于 obj 自身上。
const obj = {};
Object.defineProperty(obj3, 'value', {
get: function() {
return 'getter';
}
});
console.log(obj3.value); // 输出 'getter'
// 显式地将属性定义在对象的原型上
function MyClass() {}
Object.defineProperty(MyClass.prototype, 'value', {
get: function() {
return 'getter';
}
set: function(newValue) {
this._value = newValue;
},
enumerable: true,
configurable: true
});
const obj = new MyClass();
console.log(obj.value); // 输出 'getter'
-
enumerable
:- 为
true
时,该属性可以在对象的枚举属性中被枚举到(默认情况为true)。 - 为
false
,则该属性将不会出现在枚举中,例如在for...in
循环中或通过Object.keys()
方法获取对象的键时不会包含该属性。
- 为
-
configurable
:- 为
true
时,该属性可以被删除,属性的特性也可以被修改。 - 为
false
,则该属性不能被删除,属性的特性也不能再次修改,且无法再将其改为true
。 - 默认情况是 false:为了保护对象的一致性和完整性,防止意外修改或删除重要属性
- 为
set(setter)
set
语法将对象属性绑定到要调用的函数,简称修改属性值的时候调用绑定的函数。
语法
创建
{ set prop(val) { /* … */ } }
{ set [expression](val) { /* … */ } }
参数说明:
prop
: 要绑定到给定函数的属性名,即对哪个属性名进行监听val
: 保存尝试分配给**prop
的值**的变量的一个别名expression
: 使用一个计算属性名的表达式绑定到给定的函数。
注意事项:
-
必须有一个明确的参数
-
在对象字面量中,不能为一个已有真实值的变量使用 set,也不能为一个属性设置多个 set。 (
{ set x(v) { }, set x(v) { } }
和{ x: ..., set x(v) { } }
是不允许的 )。
删除
删除使用delete
,就可删除setter
实例
// { set prop(val) { /* … */ } }
const language = {
set current(name) {
this.log.push(name);
},
log: [],
};
language.current = "EN";
console.log(language.log); // ['EN']
language.current = "FA";
console.log(language.log); // ['EN', 'FA']
// { set [expression](val) { /* … */ } }
const expr = "foo";
const obj = {
baz: "bar",
set [expr](v) {
this.baz = v;
},
};
console.log(obj.baz); // "bar"
obj.foo = "baz"; // run the setter
console.log(obj.baz); // "baz"
// 删除
delete language.current;
getter
:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/get
setter
:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/set