赞
踩
目录
使用getter和setter来封装一个对象的内部状态,防止直接访问和修改。
通过设置writable为false,可以创建一个不允许修改的属性。
在setter中添加逻辑来验证属性值,确保它们满足特定条件。
三、情景:如果属性描述符中writable为false,但是写了set函数
请注意,本文讲述的是JS中的属性描述符,不是Python中的属性描述符
属性描述符(Property Descriptor)在JavaScript中是一个特殊的对象,它定义了对象属性的行为和特性。
属性描述符是一个对象,它通常包含以下几个属性:
- value:属性的值。这是一个数据属性的特性,用于存储属性值。
- writable:一个布尔值,表示属性的值是否可被修改。如果设置为false,属性值将不可修改。
- get:一个函数,当访问属性时调用,用于获取属性值。这是一个访问器属性的特性。
- set:一个函数,当设置属性值时调用,用于设置属性值。这是一个访问器属性的特性。
- enumerable:一个布尔值,表示属性是否可被枚举,默认为false。如果设置为true,则属性会显示在for-in循环和Object.keys()的结果中。
- configurable:一个布尔值,表示属性的属性描述符是否可以被改变,以及属性是否可以被删除。如果设置为false,属性将不能被删除,且其属性描述符不能被改变。
属性描述符的属性树如下:
属性描述符示例如下:
- let descriptor = {
- value: 42,
- writable: true,
- enumerable: true,
- configurable: true
- };
在这个例子中,descriptor是一个属性描述符对象,它定义了一个数据属性,该属性具有可写的值、可枚举和可配置的特性。
要使用属性描述符来定义或修改对象属性,可以使用Object.defineProperty()方法,此外,还可以使用Object.getOwnPropertyDescriptor()来获取对象属性的当前属性描述符
- let obj = {};
-
- Object.defineProperty(obj, 'myProp', {
- value: 42,
- writable: true,
- enumerable: true,
- configurable: true
- });
-
- // 获取对象属性的当前属性描述符
-
- let propDesc = Object.getOwnPropertyDescriptor(obj, 'myProp');
-
- console.log(propDesc);
-
- // 输出:{ value: 42, writable: true, enumerable: true, configurable: true }
带有读取器(getter)和设置器(setter)的属性描述符允许你定义属性的获取和设置行为,而不是直接存储一个值。这种属性被称为访问器属性。以下是一个带有读取器和设置器的属性描述符的例子:
- let obj = {};
-
- // 定义属性描述符,包含读取器和设置器
- let descriptor = {
- get: function() {
- // 这个函数会在访问属性时被调用
- console.log('Getting the value!');
- return this._myValue; // 访问器返回内部属性的值
- },
- set: function(newValue) {
- // 这个函数会在设置属性值时被调用
- console.log('Setting the value to ' + newValue);
- this._myValue = newValue; // 设置器将值存储到内部属性
- },
- enumerable: true, // 属性是否可枚举
- configurable: true // 属性的描述符是否可以被改变
- };
-
- // 使用属性描述符定义属性
- Object.defineProperty(obj, 'myProperty', descriptor);
-
- // 测试读取器
- console.log(obj.myProperty); // 输出: 'Getting the value!' 然后是 undefined
-
- // 测试设置器
- obj.myProperty = 10; // 输出: 'Setting the value to 10'
- console.log(obj.myProperty); // 输出: 'Getting the value!' 然后是 10
其中,对obj中myProperty属性进行赋值,就会触发设置器,读取obj的myProperty属性,就会触发读取器。
- // 使用getter和setter来封装一个对象的内部状态,防止直接访问和修改。
-
- let user = {
- _name: 'Alice',
- get name() {
- return this._name;
- },
- set name(value) {
- if (typeof value === 'string') {
- this._name = value;
- } else {
- console.log('Name must be a string.');
- }
- }
- };
-
- console.log(user.name); // Alice
- user.name = 'Bob'; // 更新名称
- console.log(user.name); // Bob
- user.name = 123; // 尝试设置非法名称,将显示错误信息
- // 通过设置writable为false,可以创建一个不允许修改的属性。
-
- let product = {
- _price: 19.99,
- get price() {
- return this._price;
- }
- };
-
- Object.defineProperty(product, 'price', {
- writable: false,
- enumerable: true,
- configurable: true
- });
-
- console.log(product.price); // 19.99
- // product.price = 24.99; // 这将不会改变价格,因为属性是只读的
- // 在setter中添加逻辑来验证属性值,确保它们满足特定条件。
-
- let account = {
- _balance: 0,
- get balance() {
- return this._balance;
- },
- set balance(amount) {
- if (amount < 0) {
- console.log('Cannot set a negative balance.');
- } else {
- this._balance = amount;
- }
- }
- };
-
- account.balance = 1000; // 设置余额
- console.log(account.balance); // 1000
- account.balance = -500; // 尝试设置负余额,将显示错误信息
如果属性描述符中的 writable 属性设置为 false,这意味着属性的值不能被重新赋值。此时如果尝试通过 set 函数修改属性值,它将不会对属性的实际值产生任何影响,因为 writable 属性已经明确禁止了对值的修改。
- let obj = {};
-
- let descriptor = {
- value: 42,
- writable: false, // 禁止修改属性值
- set: function(newValue) {
- console.log(`Attempt to set value to: ${newValue}`);
- // 尽管这里尝试设置新值,但由于 writable: false,这个操作不会有任何效果
- // 甚至连`Attempt to set value to: ${newValue}`都不会打印
- // writable: false情况下,不会触发设置器函数
- },
- enumerable: true,
- configurable: true
- };
-
- Object.defineProperty(obj, 'myProperty', descriptor);
-
- console.log(obj.myProperty); // 输出: 42
-
- obj.myProperty = 100; // 尝试修改属性值,但会失败
- // "Attempt to set value to: 100" 这一行不会被打印
- console.log(obj.myProperty); // 输出仍然是: 42
-
-
- obj.myProperty = 'new value'; // 再次尝试修改属性值,但仍然会失败
- console.log(obj.myProperty); // 输出仍然是: 42
-
属性描述符还有很多内容可以挖掘,比如defineProperty与Proxy的区别,比如vue2与vue3实现数据劫持的方式有什么不同,实现效果有哪些差异等,这篇博文只是入门,以后有时间再深挖。
博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
更多优质内容,请关注:
JS底层逻辑:
最细最有条理解析:事件循环(消息循环)是什么?进程与线程的定义、关系与差异
JS语法篇:
你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解
通过array.every()实现数据验证、权限检查和一致性检查,array.some与array.every的区别
通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理
通过array.map()实现数据转换、创建派生数组、异步数据流处理、搜索和过滤等需求
通过array.reduce()实现数据汇总、条件筛选和映射、对象属性的扁平化、转换数据格式等
通过array.filter()实现数组的数据筛选、数据清洗和链式调用
巧妙算法与窍门:
多维数组操作,不要再用遍历循环foreach了,来试试数组展平的小妙招!
shpfile转GeoJSON且控制转化精度;如何获取GeoJSON?GeoJson结构详解
Mapbox添加行政区矢量图层、分级设色图层、自定义鼠标悬浮框、添加天地图底图等
Element plus拓展:
通过el-tree自定义渲染网页版工作目录,实现鼠标悬浮显示完整名称等
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。