js中的Object.defineProperty()详解

文章目录

  • 一、Object.defineProperty()
  • 二、descriptor属性描述符
    • 2.1、数据描述符
    • 2.2、访问器描述符
    • 2.3、descriptor属性
      • 2.3.1、value
      • 2.3.2、writable
      • 2.3.3、enumerable (可遍历性)
      • 2.3.4、configurable (可配置性)
  • 三、注意事项

一、Object.defineProperty()

Object.defineProperty() 方法允许精确地添加或修改对象的属性,并返回此对象。默认情况下,使用此方法添加的属性是不可修改的。

基本语法

Object.defineProperty(obj, prop, descriptor)

参数说明:

  • obj: 要定义属性的对象
  • prop: 要定义或修改的属性名
  • descriptor: 属性描述符对象

descriptor 对象包含以下属性:

  • value:属性的值,默认为undefined
  • writable:属性的可写性。默认为false,即该属性为只读属性。
  • enumerable:属性的可枚举性。默认为false,即该属性不可枚举。
  • configurable:属性的可配置性。默认为false,即该属性不可被删除。
  • get:获取属性值的函数。
  • set:设置属性值的函数。

返回值

  • 传入函数的对象,其指定的属性已被添加或修改。

二、descriptor属性描述符

对象中存在的属性描述符有两种主要类型:数据描述符访问器描述符

  • 数据描述符是一个具有可写或不可写值的属性。
  • 访问器描述符是由 getter/setter 函数对描述的属性。

描述符只能是这两种类型之一,不能同时为两者
在这里插入图片描述

2.1、数据描述符

const obj = {};Object.defineProperty(obj, 'name', {value: 'John',          // 属性值writable: true,         // 是否可写enumerable: true,       // 是否可枚举configurable: true      // 是否可配置
});

html代码如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script type="text/javascript">const obj = {};Object.defineProperty(obj, 'name', {value: 'John',          // 属性值writable: true,         // 是否可写enumerable: true,       // 是否可枚举configurable: true      // 是否可配置});console.log(obj)</script></body>
</html>

运行后控制台输出:
在这里插入图片描述

2.2、访问器描述符

const obj = {_name: 'John'
};Object.defineProperty(obj, 'name', {get() {return this._name;},set(value) {this._name = value;},enumerable: true,configurable: true
});

2.3、descriptor属性

2.3.1、value

value: 属性的值,可以是任何有效的 JavaScript 值(数值,对象,函数等),不设置的话默认为 undefined

let person = {name: "张三",sex: "男",};Object.defineProperty(person, 'age', {value: 18,})console.log(person); // {name: '张三', sex: '男', age: 18}
person.age=20;  //设置更改年龄,但是发现更改失败,因为writable属性默认为false
console.log(person);

2.3.2、writable

writable 是一个布尔值,决定了目标属性的值(value)是否可以被改变。

● writable默认为false, 当 writable 设置为 false 时,使用 赋值运算符 修改属性的值,不会报错,但也不会生效。

let person = {name: "张三",sex: "男",
};
Object.defineProperty(person, 'age', {value: 18,
})console.log(person); // {name: '张三', sex: '男', age: 18}
person.age=20;  //设置更改年龄,但是发现更改失败,因为writable属性默认为false
console.log(person);// {name: '张三', sex: '男', age: 18}  输出后还是18

● 当 writable 设置为 false 时,使用 Object.defineProperty() 修改属性的值,会直接报错。

let person = {name: "张三",sex: "男",
};
Object.defineProperty(person, 'age', {value: 18,writable:true
})console.log(person); // {name: '张三', sex: '男', age: 18}Object.defineProperty(person, 'age', {value: 20
}) //抛错 Uncaught SyntaxError: Identifier 'person' has already been declaredconsole.log(person);

● writable设置为true,使用 赋值运算符或者 Object.defineProperty() 都可以修改属性的值。

let person = {name: "张三",sex: "男",
};
Object.defineProperty(person, 'age', {value: 18,writable:true
})console.log(person); // {name: '张三', sex: '男', age: 18}
person.age=20;  //设置更改年龄
console.log(person); // {name: '张三', sex: '男', age: 20}Object.defineProperty(person, 'age', {value: 21
})
console.log(person); // {name: '张三', sex: '男', age: 21}

2.3.3、enumerable (可遍历性)

enumerable 是一个布尔值,表示目标属性在 for…in、Object.keys、JSON.stringify 中是否可遍历。

● 当 enumerable 设置为 true 时,目标属性可被遍历操作。

let person = {name: "张三",sex: "男",
};
Object.defineProperty(person, 'age', {value: 18,enumerable:true
})for (const key in person) {console.log(' for in', key);
}
console.log('Object.keys:', Object.keys(person));
console.log('JSON.stringify:', JSON.stringify(person));

在这里插入图片描述
● 当 enumerable 设置为 false 时,目标属性不可被遍历操作。

let person = {name: "张三",sex: "男",
};
Object.defineProperty(person, 'age', {value: 18,enumerable:false
})for (const key in person) {console.log(' for in', key);  //只输出name, sex,不会输出age
}
console.log('Object.keys:', Object.keys(person));
console.log('JSON.stringify:', JSON.stringify(person));

在这里插入图片描述
● for…in 循环包括继承的属性,Object.keys 方法不包括继承的属性。如果需要获取对象自身的所有属性,不管是否可遍历,可以使用 Object.getOwnPropertyNames 方法。

2.3.4、configurable (可配置性)

configurable 是一个布尔值,决定了是否可以修改 属性描述对象 以及表示能否通过 delete 删除属性。

● 当 configurable 为 false 时,不能否通过 delete 删除属性。

// 定义对象
const myObject = {};
// 设置 configurable 为 false
Object.defineProperty(myObject, 'firstName', {
value: 'first',
configurable: false,
});
// 设置 configurable 为 true
Object.defineProperty(myObject, 'lastName', {
value: 'last',
configurable: true,
});
console.log('before delete ~ myObject.firstName :', myObject.firstName);
console.log('before delete ~ myObject.lastName :', myObject.lastName);
delete myObject.firstName
delete myObject.lastName
console.log('after delete ~ myObject.firstName :', myObject.firstName);
console.log('after delete ~ myObject.lastName :', myObject.lastName);

在这里插入图片描述

可以看到 configurable 为 false 时,delete 属性不会报错,但也不会生效。

可以看到 configurable 为 true 时,delete 属性会生效,属性变为 undefined。

● 当 configurabletrue 并且 writabletrue 时,通过 赋值运算符 修改 value 的修改才会生效。

// 定义对象
const myObject = {};
// 设置 configurable 为 true,writable 默认为 false
Object.defineProperty(myObject, 'firstName', {value: 'han',configurable: true,
});
// 设置 configurable 为 true,writable 为 true
Object.defineProperty(myObject, 'lastName', {value: 'zhiwei',configurable: true,writable: true,
});
console.log('before change ~ myObject.firstName :', myObject.firstName); //han
myObject.firstName = 'zhang'
console.log('after change ~ myObject.firstName :', myObject.firstName); //han 没有生效console.log('before change ~ myObject.lastName :', myObject.lastName); //zhiwei
myObject.lastName = 'san'
console.log('after change ~ myObject.lastName :', myObject.lastName); //san 生效了

● 当 configurable 何 writable 其中有任意一个为 true 时,通过 Object.defineProperty() 方法修改属性的值,就会生效。

// 定义对象
const myObject = {};
// 设置 configurable 为 true,writable 为 false
Object.defineProperty(myObject, 'firstName', {value: 'han',configurable: true,writable: false
});
Object.defineProperty(myObject, 'firstName', {value: 'wang',
});
console.log('myObject.firstName:', myObject.firstName); // wang
// 定义对象
const myObject = {};
// 设置 configurable 为 false,writable 为 true
Object.defineProperty(myObject, 'firstName', {value: 'han',configurable: false,writable: true
});
Object.defineProperty(myObject, 'firstName', {value: 'wang',
});
console.log('myObject.firstName:', myObject.firstName); // wang

● 当 configurable 为 false 时, enumerable, configurable 都不可修改,会直接报错。

// 定义对象
const myObject = {};
// 设置 enumerable 为 trueObject.defineProperty(myObject, 'firstName', {value: 'han',configurable: false,enumerable: true,
});
// 设置 enumerable 为 falseObject.defineProperty(myObject, 'firstName', {value: 'wang',configurable: false,enumerable: false,
});
console.log('Descriptor:', Object.getOwnPropertyDescriptor(myObject, 'firstName'));

● 当 configurable 为 false 时, writable 可以由 true 改为 false ,但不可由 false 改为 true ,否则会报错。

// 定义对象
const myObject = {};
// 设置 writable 为 trueObject.defineProperty(myObject, 'firstName', {value: 'han',configurable: false,writable: true
});
// 设置 writable 为 falseObject.defineProperty(myObject, 'firstName', {value: 'wang',configurable: false,writable: false,
});
console.log('Descriptor:', Object.getOwnPropertyDescriptor(myObject, 'firstName'));

● 当 configurable 为 false 时, getter 和 setter 方法无法被修改。

// 定义对象 
const myObject = {};
Object.defineProperty(myObject, 'firstName', {configurable: false,get() {console.log('读取了 myObject.firstName:');return this.value;},set(newValue) {console.log('修改了 myObject.firstName:');this.value = newValue;},
});
Object.defineProperty(myObject, 'firstName', {configurable: false,get() {console.log('读取了 myObject.firstName:');return this.value + 'y';},set(newValue) {console.log('修改了 myObject.firstName:');this.value = newValue + 'y';},
});

三、注意事项

注意事项:
Object.defineProperty() 设置了getter和setter方法之后,就不能再设置value属性,否则控制台报错:Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object>



参考或推荐文档:
1.Object.defineProperty
2.https://www.jb51.net/javascript/3335118jy.htm
3.https://blog.51cto.com/u_12379999/13028626

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/67203.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【搭建JavaEE】(2)Tomcat安装配置和第一个JavaEE程序

Tomcat–容器(Container) 下载 Apache Tomcat - Welcome! 下载完成 请求/响应 结构 测试 查看Jdk版本 改端口号localhost8080–>8099 学学人家以后牛逼了可以用自己名字当文件夹名 配置端口8099 找到server文件 用记事本打开 再打开另一个logging文件 ”乱码解决“步骤&…

RPC 源码解析~Apache Dubbo

解析 RPC&#xff08;远程过程调用&#xff09;的源码可以帮助你深入理解其工作原理和实现细节。为了更好地进行源码解析&#xff0c;我们选择一个流行的 RPC 框架——Apache Dubbo 作为示例。Dubbo 是一个高性能、轻量级的开源 Java RPC 框架&#xff0c;广泛应用于企业级应用…

centos7.6 安装nginx 1.21.3与配置ssl

1 安装依赖 yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel2 下载Nginx wget http://nginx.org/download/nginx-1.21.3.tar.gz3 安装目录 mkdir -p /data/apps/nginx4 安装 4.1 创建用户 创建用户nginx使用的nginx用户。 #添加www组 # groupa…

高级软件工程-复习

高级软件工程复习 坐标国科大&#xff0c;下面是老师说的考试重点。 Ruby编程语言的一些特征需要了解要能读得懂Ruby程序Git的基本命令操作知道Rails的MVC工作机理需要清楚&#xff0c;Model, Controller, View各司什么职责明白BDD的User Story需要会写&#xff0c;SMART要求能…

TrollFools 2.10-22 插件注入工具 官方版

《TrollFools巨魔设备专用插件注入工具》这是一款专为巨魔设备打造的插件注入神器&#xff0c;功能强大且操作便捷。它能够轻松地将插件注入通过AppStore商店下载的任意APP中&#xff0c;同时也能随时卸载&#xff0c;丝毫不影响APP的正常使用。注入后的APP仍可正常更新&#x…

30分钟内搭建一个全能轻量级springboot 3.4 + 脚手架 <1> 5分钟快速创建一个springboot web项目

快速导航 <1> 5分钟快速创建一个springboot web项目 <2> 5分钟集成好最新版本的开源swagger ui&#xff0c;并使用ui操作调用接口 <3> 5分钟集成好druid并使用druid自带监控工具监控sql请求 <4> 5分钟集成好mybatisplus并使用mybatisplus generator自…

软考信安20~数据库系统安全

1、数据库安全概况 1.1、数据库安全概念 数据库是网络信息系统的基础性软件,承载着各种各样的数据,成为应用系统的支撑平台。 国外主流的数据库系统有MSSQL 、MySQL 、Oracle 、DB2 等,国产数据库系统主要有人大金仓、达梦等。 1.2、数据库安全威胁 授权的误用(Misuses…

Python脚本自动发送电子邮件

要编写一个Python脚本来自动发送电子邮件&#xff0c;你可以使用smtplib库来处理SMTP协议&#xff0c;以及email库来构建邮件内容。 安装必要的库 通常情况下&#xff0c;smtplib和email库是Python标准库的一部分&#xff0c;因此不需要额外安装。如果你使用的是较旧的Python版…

按键精灵ios越狱脚本教程:多选框联动的ui界面

以下是一个简单的 iOS 代码示例&#xff0c;使用 Swift 语言来创建一个包含多选框&#xff08;复选框&#xff09;的 UI 界面&#xff0c;并实现联动效果。 import UIKitclass ViewController: UIViewController {let checkbox1 UIButton(type:.system)let checkbox2 UIButt…

arcgis中生成格网矢量带高度

效果 1、数据准备 (1)矢量边界(miain.shp) (2)DEM(用于提取格网标高) (3)DSM(用于提取格网最高点) 2、根据矢量范围生成格网 模板范围选择矢量边界,像元宽度和高度根据坐标系来输入,我这边是4326的,所以输入的是弧度,输出格网矢量gewang.shp 3、分区统计 …

ubuntu20升级至22后不兼容ssh-rsa加密算法

背景 升级ubuntu20后22后&#xff0c;远程连接工具无法通过public key方式登录主机。 分析&解决 查看sshd服务有报错journatl -xeu sshd 1月 10 19:10:01 k8s-master03 sshd[21093]: userauth_pubkey: key type ssh-rsa not in PubkeyAcceptedAlgorithms [preauth] 1月 …

C#的Task

优先使用Task.Run&#xff0c;除非有定制化需求才用Task.Factory.StartNew Task.Factory.StartNew的TaskScheduler参数颠覆你的认知&#xff1a; var cnt 0;var cancelToken new CancellationTokenSource();await Task.Factory.StartNew(() > {cnt;Debug.WriteLine($&quo…

JavaScript 实现继承的详细方法:深入探讨

文章目录 前言一、原型链 (Prototype Chain)二、借用构造函数 (Constructor Stealing / Classical Inheritance)三、组合式继承 (Combination Inheritance)四、原型式继承 (Prototypal Inheritance)五、寄生式继承 (Parasitic Inheritance)六、ES6 类 (Class) 和 extends 关键字…

海豚调度DolphinScheduler-3.1.9配置windows本地开发环境

源代码下载地址https://dolphinscheduler.apache.org/zh-cn/docs/3.1.9 1.Zookeeper安装与使用 如图下载解压zookeeper安装包&#xff0c;并创建data和log目录 下载地址 https://archive.apache.org/dist/zookeeper/zookeeper-3.6.4/apache-zookeeper-3.6.4-bin.tar.gz 进入…

P1图文解析:初识算法和数据结构

文章目录 前言1、算法例子1.1、查字典&#xff08;二分查找算法&#xff09;1.2、整理扑克&#xff08;插入排序算法&#xff09;1.3、货币找零&#xff08;贪心算法&#xff09; 2、算法与数据结构2.1、算法定义2.2、数据结构定义2.3、数据结构与算法的关系2.4、独立于编程语言…

校园跑腿小程序---轮播图,导航栏开发

hello hello~ &#xff0c;这里是 code袁~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的在校大学生…

C# 中对 Task 中的异常进行捕获

以下是在 C# 中对 Task 中的异常进行捕获的几种常见方法&#xff1a; 方法一&#xff1a;使用 try-catch 语句 你可以使用 try-catch 语句来捕获 Task 中的异常&#xff0c;尤其是当你使用 await 关键字等待任务完成时。 using System; using System.Threading.Tasks;class …

UE材质节点Fresnel

Fresnel节点 ExponentIn 控制边缘透明度 BaseReflectFractionIn 控制中心透明度

大数据学习(34)-mapreduce详解

&&大数据学习&& &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 承认自己的无知&#xff0c;乃是开启智慧的大门 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博主哦&#x1f91…

浅谈云计算07 | 云安全机制

浅谈云计算安全机制&#xff1a;全方位守护云端世界 一、引言二、加密技术&#xff1a;数据的隐形护盾三、散列机制&#xff1a;数据完整性的忠诚卫士四、数字签名&#xff1a;数据来源与真伪的鉴定专家五、公钥基础设施&#xff08;PKI&#xff09;&#xff1a;信任的基石六、…