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文件 ”乱码解决“步骤&…

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自…

arcgis中生成格网矢量带高度

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

海豚调度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;一名喜欢分享和记录学习的在校大学生…

UE材质节点Fresnel

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

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

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

Notepad++上NppFTP插件的安装和使用教程

一、NppFTP插件下载 图示是已经安装好了插件。 在搜索框里面搜NppFTP&#xff0c;一般情况下&#xff0c;自带的下载地址容易下载失败。这里准备了一个下载连接&#xff1a;Release v0.29.10 ashkulz/NppFTP GitHub 这里我下载的是x86版本 下载好后在nodepad的插件里面选择打…

高级运维:源码编译安装httpd 2.4,提供系统服务管理脚本并测试

1.下载httpd 2.4 源码 wget https://archive.apache.org/dist/httpd/httpd-2.4.54.tar.gz 2.解压下载压缩包 tar -zxvf httpd-2.4.54.tar.gz cd httpd-2.4.54 3.安装httpd需要的依赖包 sudo yum groupinstall "Development Tools" -y sudo yum install gcc glibc ap…

8.Bridge 桥接模式(结构型模式)

【1】抽象A>实现细节b 【2】抽象A>抽象B<实现细节b 【3】【抽象B】相对稳定&#xff0c;也可能变化 【实现细节b】频繁变化 【4】抽象B 不稳定&#xff1f; 思考问题&#xff1a;一个变化是平台&#xff08;抽象B&#xff09;的变化&#xff0c;另一个变化是型号…

【PyQt】如何在mainwindow中添加菜单栏

[toc]如何在mainwindow中添加菜单栏 如何在mainwindow中添加菜单栏 主要有两种方法&#xff1a; 1.直接创建mainwindow进行添加 2.使用ui文件加载添加 第二种方法更为常见&#xff0c;可以应用到实际 1.直接创建mainwindow进行添加 import sysfrom PyQt5.QtWidgets import …

基于springboot+vue+微信小程序的宠物领养系统

基于springbootvue微信小程序的宠物领养系统 一、介绍 本项目利用SpringBoot、Vue和微信小程序技术&#xff0c;构建了一个宠物领养系统。 本系统的设计分为两个层面&#xff0c;分别为管理层面与用户层面&#xff0c;也就是管理者与用户&#xff0c;管理权限与用户权限是不…

【Rust】错误处理机制

目录 思维导图 引言 一、错误处理的重要性 1.1 软件中的错误普遍存在 1.2 编译时错误处理要求 二、错误的分类 2.1 可恢复错误&#xff08;Recoverable Errors&#xff09; 2.2 不可恢复错误&#xff08;Unrecoverable Errors&#xff09; 三、Rust 的错误处理机制 3…

Spring Boot教程之五十五:Spring Boot Kafka 消费者示例

Spring Boot Kafka 消费者示例 Spring Boot 是 Java 编程语言中最流行和使用最多的框架之一。它是一个基于微服务的框架&#xff0c;使用 Spring Boot 制作生产就绪的应用程序只需很少的时间。Spring Boot 可以轻松创建独立的、生产级的基于 Spring 的应用程序&#xff0c;您可…

金融项目实战 04|JMeter实现自动化脚本接口测试及持续集成

目录 一、⾃动化测试理论 二、自动化脚本 1、添加断言 1️⃣注册、登录 2️⃣认证、充值、开户、投资 2、可重复执行&#xff1a;清除测试数据脚本按指定顺序执行 1️⃣如何可以做到可重复执⾏&#xff1f; 2️⃣清除测试数据&#xff1a;连接数据库setup线程组 ①明确…

【Uniapp-Vue3】@import导入css样式及scss变量用法与static目录

一、import导入css样式 在项目文件中创建一个common文件夹&#xff0c;下面创建一个css文件夹&#xff0c;里面放上style.css文件&#xff0c;编写的是公共样式&#xff0c;我们现在要在App.vue中引入该样式。 在App.vue中引入该样式&#xff0c;这样就会使样式全局生效&#…