序言
我想向您的法院展示一些微型雕像,它们将描述元编程的技术和基本原理。 我将主要介绍在JavaScript或TypeScript中使用某些技术的情况。
这是该系列的第一篇(希望不是最后一篇)。
那么什么是元编程
元编程是一种编程技术,其中计算机程序具有将其他程序视为其数据的能力。 这意味着可以将程序设计为读取,生成,分析或转换其他程序,甚至在运行时对其进行修改。 在某些情况下, 这使程序员可以最大程度地减少表达解决方案的代码行数,从而减少开发时间 。
一个相当混乱的描述,但是元编程的主要好处是可以理解的:
...这使程序员可以最大程度地减少实施解决方案的代码行数,从而减少开发时间

实际上,元编程有很多面子和幌子。 而且,您可以就“元编程的结束位置和编程本身的开始位置”进行长时间的讨论。
对于我自己,我接受以下规则:
- 元编程不会处理业务逻辑,不会更改它,也不会以任何方式影响它。
- 如果删除所有元编程代码,则这不会(根本)影响程序。
在JavaScript中,元编程是一个相对较新的趋势,其基本组成部分是描述符。
JavaScript描述符
描述符是对象中某种属性或方法的一种描述(元信息)。
理解和适当地操纵该对象( 描述符 )不仅可以创建和更改对象中的方法或属性,还可以做更多的事情。
描述符也将有助于理解装饰器的工作(但在下一篇文章中有更多介绍)。
为了清楚起见,假设我们的对象是公寓的描述。
我们描述了我们公寓的目的:
let apt = { floor: 12, number: '12B', size: 3400, bedRooms: 3.4, bathRooms: 2, price: 400000, amenities: {...} };
让我们确定哪些属性是可修改的,哪些属性是不可修改的。
例如,楼层或公寓的总大小无法更改,但是房间或浴室的数量是完全可能的。
因此,我们有以下要求:在apt对象中,无法更改属性: floor和size 。
为了解决这个问题,我们只需要每个属性的描述符即可。 要获取描述符 ,我们使用静态方法getOwnPropertyDescriptor ,该方法属于Object类。
let descriptor = Object.getOwnPropertyDescriptor(todoObject, 'floor'); console.log(descriptor);
让我们按顺序分析:
值:任何 -实际上在某个时候分配给floor属性的值相同
可写:布尔值 -确定是否更改值
枚举:布尔值 -确定floor属性是否可以列出-(稍后会详细介绍)。
可配置:布尔值 -定义对描述符对象进行更改的能力。
为了防止更改floor属性的可能性,初始化后,必须将writable的值更改为false 。
要更改描述符的属性,有一个静态方法defineProperty ,它使用对象本身,属性的名称和描述符 。
Object.defineProperty(apt, 'floor', {writable: false});
在此示例中,我们不传递整个描述符对象,而仅传递一个值为false的 可写属性。
现在,让我们尝试更改floor属性的值:
apt.floor = 44; console.log(apt.floor);
该值未更改,使用'use strict'时,我们收到一条错误消息:
无法分配为只读对象的属性“ floor” ...
现在,我们不能再更改该值。 但是,我们仍然可以返回writable-> true ,然后更改floor属性。 为了避免这种情况,有必要在描述符中将可配置属性的值更改为false 。
Object.defineProperty(apt, 'floor', {writable: false, configurable: false});
如果我们现在尝试更改描述符的任何属性的值,则...
Object.defineProperty(apt, 'floor', {writable: true, configurable: true});
作为回应,我们得到:
TypeError:无法重新定义属性:floor
换句话说,我们既不能更改floor的值也不能更改其描述符 。
总结一下
要使对象中的属性值不变,必须注册此属性的配置: {writable:false,configurable:false} 。
这可以在属性初始化期间完成:
Object.defineProperty(apt, 'floor', {value: 12, writable: false, configurable: false});
或之后。
Object.defineProperty(apt, 'floor', {writable: false, configurable: false});
最后,考虑一个带有类的示例:
class Apartment { constructor(apt) { this.apt = apt; } getFloor() { return this.apt.floor } } let apt = { floor: 12, number: '12B', size: 3400, bedRooms: 3.4, bathRooms: 2, price: 400000, amenities: {...} };
更改getFloor方法:
Apartment.prototype.getFloor = () => { return 44 }; let myApt = new Apartment(apt); console.log(myApt);
现在更改getFloor()方法的描述符 :
Object.defineProperty(Apartment.prototype, 'getFloor', {writable: false, configurable: false}); Apartment.prototype.getFloor = () => { return 44 }; let myApt = new Apartment(apt); console.log(myApt);
我希望本文能进一步说明什么是描述符以及如何使用它。
上面写的所有内容均不主张绝对正确或唯一正确。