对象属性的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 引入了getset,允许开发者定义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;

getterhttps://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/get

setterhttps://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/set

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
计算属性是一种特殊的属性,它的值是通过计算而得到的,而不是直接存储在对象。在访问计算属性时,会触发一个特定的方法来计算并返回属性的值。计算属性通常用于对其他属性进行处理或者根据某些条件动态计算属性的值。 计算属性可以拥有一个名为`get`的方法来定义属性的获取行为。这个方法会在访问该属性时自动调用,并返回计算得到的属性值。例如,假设有一个对象`person`,包含`firstName`和`lastName`两个属性,我们可以通过计算属性来获取完整的姓名: ```javascript const person = { firstName: 'John', lastName: 'Doe', get fullName() { return this.firstName + ' ' + this.lastName; } }; console.log(person.fullName); // 输出: John Doe ``` 在上面的例子,`fullName`是一个计算属性,它通过拼接`firstName`和`lastName`来计算得到完整的姓名。 除了`get`方法外,计算属性还可以拥有一个名为`set`的方法来定义属性的设置行为。当对计算属性进行赋值时,`set`方法会被调用,并传入新的属性值作为参数。通过这个方法,我们可以对赋值操作进行一些处理或者更新其他相关的属性。例如: ```javascript const person = { firstName: 'John', lastName: 'Doe', get fullName() { return this.firstName + ' ' + this.lastName; }, set fullName(value) { const parts = value.split(' '); this.firstName = parts[0]; this.lastName = parts[1]; } }; person.fullName = 'Jane Smith'; console.log(person.firstName); // 输出: Jane console.log(person.lastName); // 输出: Smith ``` 在上面的例子,我们通过`set`方法将一个字符串值分割为`firstName`和`lastName`,并分别进行赋值。 需要注意的是,计算属性只能通过`get`和`set`方法来访问和修改,而不能直接通过对象属性名来操作。另外,计算属性不会被序列化,也不会在对象原型被继承。对于只读的计算属性,只需要定义`get`方法而不定义`set`方法即可。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值