js 对象属性的特性

本文介绍了JavaScript中对象属性的特性,包括数据属性和访问器属性的详细说明,如configurable、enumerable、writable、get和set等,并提供了如何通过Object.getOwnPropertyDescriptor()和Object.defineProperty()进行修改和读取属性特性的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

“js 对象属性的特性”的学习笔记,介绍属性特性的种类和说明,以及如何获取和修改属性特性。


在 js 中,可以把对象想象成一个散列表(类似于 Python 中的字典类型,或者是 Java 中的 HashMap),其中的内容就是一组名/值对,值可以是数据或者函数

一、创建简单的对象

创建一个简单的对象主要有两种方法,第一种是先创建一个 Object 实例,然后给这个实例添加属性和方法:

let person = new Object();
person.name = "ec50n9";
person.age = 19;
person.sayName = function(){
  console.log(this.name);
};

这样就创建好一个名为 person 的对象了,它包含有 nameagesayName 三个属性。其中 sayName 的值是一个函数,可以这样子调用:

person.sayName();     // "ec50n9"
// 👇也可以尝试一下另一种获取属性值的方式
person["sayName"]();  // "ec50n9"

还有一种看起来更加直观的创建方法,那就是使用对象字面量来创建对象,下面这种写法等价于上面的,只是看起来更简洁:

let person = {
  name: "ec50n9",
  age: 19,
  sayName(){
    console.log(this.name);
  }
};

这种写法看起来就和 Python 中的字典很类似了,实际上,如果不考虑 js 的原型链的话,它俩的用法好像确实差别不大🤪。

二、对象属性的特性

对于对象中的属性,除了可以对其赋值以外,每一个属性的内部都包含有一些内部特性来描述属性自身的特征的。

这些内部特性,开发者是无法直接访问的,只能通过 Object.defineProperty() 这个函数来对其进行修改。

不同的对象属性又有不同的内部特性,这里分开来介绍。对象的属性分两种:数据属性访问器属性

数据属性

数据属性就是最普通的属性,包含一个保存数据的位置。值都在同一个地方读写,比如这里的 name 就是一个数据属性:

let person = {
  name: "ec50n9"
};

这种属性有四个特性描述他们的行为:

1. configurable “可配置的”

默认值true

作用

  • 是否可以通过 delete 删除并重新定义
  • 是否可以修改其特性
  • 是否可以把它改为访问器属性。

解释

如果把 configurable 设置成 false,就意味着这个属性不能在对象上删除。非严格模式下对这个属性调用 delete 没有效果(返回 false),严格模式下会抛出错误。

而且,当一个属性被设置为不可配置之后,就不能再设置回可配置的了,也无法修改其他内部特性,因为 Object.defineProperty() 无法对 configurable 值为 false 的属性进行修改。

2. enumerable “可列举的”

默认值true

作用:是否可以通过 for-in 循环返回。(for-in 循环可以列举对象的属性)

3. writable “可写的”

默认值true

作用:它的值(也就是👇下面的 value 属性)是否可被修改。

4. value “值”

默认值undefined

作用:属性实际的值。

在👆上面 person.name 这个示例属性中,它的 value 就为 "ec50n9"

📜 修改方法

Object.defineProperty() 需要传入三个参数,第一个是需要修改属性的对象,第二个是属性的名称,第三个是需要修改的特性的集合

例如我想把 name 属性修改为不可枚举不可修改

// 操作前:person.name 的内部属性是这样的↙️
// ✅可修改、✅可列举、✅可写,值为"ec50n9"

Object.defineProperty(person, "name", {
  // 把可列举设置为 false
  enumerable: false,
  // 把可写设置为 false
  wirtable: false
});

// 操作过后,person.name 属性的内部特性就会发生改变,变成下面这样↙️
// ✅可修改、❌可列举、❌可写,值为"ec50n9"

person.name = "new name";  // 尝试修改
console.log(person.name);  // "ec50n9" 还是原有值,没有被改变,说明不可写。

函数的第三个参数只需传入需要修改的特性和值即可,对于没传入的特性,比如上面没有传入的 configurablevalue 这两个特性将会保持原有值不变

如果第二个参数传入的属性名是对象上没有的属性,就会为那个对象添加一个属性。例如:

// person 上面没有 age 属性
Object.defineProperty(person, "age", {
  enumerable: true,
  wirtable: true,
  value: 19
});

console.log(person)  // {name: "ec50n9", age: 19}

访问器属性

访问器属性不包含数据值,取而代之的是一个 getter 函数和一个 setter 函数,不过这两个函数都不是必须的

读取访问器属性时,会调用 getter 函数,并返回函数的返回值。

写入访问器属性的时候,会调用 setter 函数,并传入新值,由 setter 函数来决定如何处理这个新值

访问器属性也有四个特性,其中 configurableenumerable 特性和数据属性是一样的,不同的是另外两个特性被 getset 取代:

1. configurable “可配置的”

默认值true

作用:👆同数据属性一样。

2. enumerable “可列举的”

默认值true

作用:👆同数据属性一样。

3. get “获取函数”

默认值undefined

作用:获取函数,在读取属性时调用。

4. set “设置函数”

默认值undefined

作用:设置函数,在写入属性时调用。

set 函数可以为空,如果只设置了 get 函数而没有设置 set 函数的话,则意味着该属性为只读属性,尝试修改属性会被忽略(在严格模式下会抛出错误❌)。

📜 修改方法

同数据属性类似,访问器属性的特性也是通过 Object.defineProperty() 来定义的:

// 定义一个对象,包含伪私有成员 year_ 和公共成员 edition
let book = {
  year_: 2017,
  edition: 1
};

Object.defineProperty(book, "year", {
  get(){
    // 直接返回 year_ 的值
    return this.year_;
  },
  set(newValue){
    // 对新的值进行判断
    if(newValue > 2017){
      // 把 year_ 设置为新的值
      this.year_ = newValue;
      // 同时修改 edition 的值
      this.edition += newValue - 2017;
    }
  }
});

year_ 中的下划线常用来表示该属性并不希望在对象方法的外部被访问。实际上,你仍可以在外部像访问普通属性一样访问到 year_,这只是一个约定,没有真的隐藏(防君子不防小人的那种)。如果想真正隐藏内部变量,可以试试闭包

通常,我们可以在 get 函数里面对即将返回的数据进行一些修饰处理什么的,也可以在 set 函数里面进行对新的值的一些验证,以防设置了一个不符合要求的值等等…

三、定义多个属性

上面用到的 Object.defineProperty() 函数每次就只能定义一个属性的特性,如果想要同时定义多个属性就需要用到 Object.defineProperties() 函数了。

例如,把上面的几个属性同时定义:

let book = {};

Object.defineProperties(book, {
  year_: {
    value: 2017
  },
  
  edition: {
    value: 1
  },
  
  year: {
    get(){
      return this.year_;
    },
    set(newValue){
      if(newValue > 2017){
        this.year_ = newValue;
        this.edition += newValue - 2017;
      }
    }
  }
});

四、读取属性的特性

读取属性可以使用Object.getOwnPropertyDescriptor(对象, 属性名) 函数。拿上面👆定义的 book 对象作示例:

// 读取一个数据属性
Object.getOwnPropertyDescriptor(book, "edition");
// 结果👇
Object {
  value: 1,
  writable: false,
  enumerable: false,
  configurable: false
}

// 再试试读取一个访问器属性
Object.getOwnPropertyDescriptor(book, "year");
// 结果👇
Object {
  get: get(),
  set: set(newValue),
  enumerable: false,
  configurable: false
}

ECMAScript 2017 新增了 Object.getOwnPropertyDescriptors(对象) 函数,从函数名后面的 s 就可以看出来,它可以获取传入对象上的全部自有属性的特性。实际上,它会在传入对象的每个自有属性上调用 Object.getOwnPropertyDescriptor() 函数,并在一个新对象中返回它们。例如:

Object.getOwnPropertyDescriptors(book);

运行结果如下:

获取全部属性的特性

以上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值