JS元编程
如果说常规编程是写代码去操作数据,那么元编程就是写代码去操作其他代码。
1 属性的特性
JS的属性有名字和值,但每个属性也有3个关联的特性:
可写(writable)特性指定是否可修改属性的值。
可枚举(enumerable)特性指定是否可以通过for/in循环和Object.keys()方法枚举属性。
可配置(configurable)特性指定是否可以删除属性,以及是否可以修改属性的特性。
这些特性允许库作者给原型对象添加方法,并让它们像内置方法一样不可枚举;允许作者“锁住”自己的对象,定义不能修改或删除的属性。
1.1 访问器属性和数值属性
访问器属性(get或set方法)没有value及writable特性,有4个特性:get、set、enumerable和configurable。
数值属性的4个特性是:value、writable、enumerable和configurable。
Object有以下方法来操作这些特性:
1) Object.getOwnPropertyDescriptor() 获取特定对象某个属性的属性描述符。
2) Object.defineProperty() 创建属性并可定义属性描述符。Object.defineProperties() 则可同时定义多个属性及其描述符。
let obj = {
get name() { return 'obj' },
x: 1
}
Object.defineProperty(obj,"y",{
value: 1,
writable: false,
enumerable: true,
configurable: false
})
Object.defineProperties(obj,{
z: {value: 1, writable: true},
age: { get: () => 18 }
})
console.log(obj);
console.log(Object.getOwnPropertyDescriptor(obj,"name"));
console.log(Object.getOwnPropertyDescriptor(obj,"z"));
console.log(Object.getOwnPropertyDescriptor(obj,"age"));
// { name: [Getter], x: 1, y: 1 }
// {
// get: [Function: get name],
// set: undefined,
// enumerable: true,
// configurable: true
// }
// { value: 1, writable: true, enumerable: false, configurable: false }
// {
// get: [Function: get],
// set: undefined,
// enumerable: false,
// configurable: false
// }
1.2 自定义深度复制函数
Object.assign()只复制可枚举属性和属性值,但不复制属性特性。这意味着如果源对象有个访问属性,那么复制到目标对象的是获取函数的返回值。
let obj = {}
Object.defineProperties(obj,{
x: { value: 1, enumerable: true ,writable: false},
y: { value: 2, enumerable: false, writable: false},
name: { get: () => "obj",enumerable: true }
})
let target = {}
Object.assign(target, obj);
console.log(target);
console.log(Object.getOwnPropertyDescriptor(target,"x"));
console.log(Object.getOwnPropertyDescriptor(target, "name"))
// { x: 1, name: 'obj' }
// { value: 1, writable: true, enumerable: true, configurable: true }
// { value: 'obj', writable: true, enumerable: true, configurable: true }
我们自定义个深度复制函数。从一个对象向另一个对象复制属性及它们的特性。
Object.defineProperty(Object, "assignDeep", {
writable: false,
enumerable: false,
configurable: false,
value: function (target, ...sourceList) {
for (let source of sourceList) {
for (let name of Object.getOwnPropertyNames(source)) {
let desc = Object.getOwnPropertyDescriptor(source,name);
Object.defineProperty(target,name,desc);
}
for (let symbol of Object.getOwnPropertySymbols(source)) {
let desc = Object.getOwnPropertyDescriptor(source, name);
Object.defineProperty(target,name,desc);
}
}
}
})
let target = {};
let source = { x: 1};
Object.defineProperties(source, {
y: { value: 2, enumerable: false},
name: {get: () => "source"},
z: { value: 3, enumerable: true}
});
Object.assignDeep(target,source);
console.log(target);
console.log(Object.getOwnPropertyDescriptor(target,"y"));
console.log(Object.getOwnPropertyDescriptor(target,"name"));
// { x: 1, z: 3 }
// { value: 2, writable: false, enumerable: false, configurable: false }
// {
// get: [Function: get],
// set: undefined,
// enumerable: false,
// configurable: false
// }
1.3 对象的可扩展能力
对象的可扩展特性控制是否可以给对象添加新属性,即是否可扩展。
Object.isExtensible() 判断一个对象是否可扩展,
Object.preventExtensions() 让对象不可扩展,只会影响对象本身,而不会影响其原型。
把对象改为不可扩展是不可逆的。
2 公认符号
是Symbol()工厂函数的一组属性,也就是一组符号值。通过这些符号值,我们可以控制js对象和类的某些底层行为。
1)hasInstance,如果instanceof 的右侧是一个有[Symbol.hasInstance]方法的对象,那么就会以左侧的值作为参数来调用这个方法并返回这个方法的值。
let bigNum = {
[Symbol.hasInstance](v) {
return v > 100
}
};
console.log(12 instanceof bigNum); // false
console.log(124 instanceof bigNum); // true
2)toStringTag, 在调用对象的toString方法时,会查找自己的参数中是否有一个属性的符号名是Symbol.toStringTag,如果有,则使用这个属性的值作为蔬菜。
class People {
get [Symbol.toStringTag]() {
return "People 人";
}
}
class Student {
}
console.log(Object.prototype.toString.call(new Student())); // [object Object]
console.log(new Student()); // {}
console.log(Object.prototype.toString.call(new People())); // [object People 人]
console.log(new People()); // People [People 人] {}
3) 模式匹配符号,match()、matchAll()、search()、replace()和split()这些字符串方法中的任意一个,都有一个与之相对应的公认符号。
class RegExtCustom {
constructor(glob) {
this.glob = glob;
}
[Symbol.search](s) {
return s.search(this.glob);
}
}
let reg = new RegExtCustom("[12]2");
console.log("1234".search(reg)); // 0
console.log("ad32".search(reg)); // -1
3 模版标签
位于反引号直接的字符串被称为“模版字面量”。如果一个函数的表达式后面跟着一个模版字面量,那就会转换为一个函数调用。
这个函数第一个参数是一个字符串数组,然后是0或多个额外任何类型的参数。如果模版字面量包含一个要插入的值,那么字符串数组就会收到2个参数,表示这个被插入值两边的字面量。(如果要插入2个值,则字符串数组会收到3个参数)。
function templateFun(strArr,...args) {
console.log("字符串数组参数:",strArr);
console.log("插入参数", args);
}
let num = 999;
let str = 'hello word';
templateFun`&${num}${str}&`;
// 字符串数组参数: [ '&', '', '&' ]
// 插入参数 [ 999, 'hello word' ]
4 反射与代理对象
ES6及之后版本中的Proxy类是JS中最强大的元编程特性。使用它可以修改JS对象的基础行为。
4.1 反射API
Reflect不是类而是对象,它的属性只是定义了一组相关函数。
1)apply(f,o,arg),将函数f作为o的方法进行调用(如果o是null,则调用函数f时没有this值),并传入args数组的值作为参数。
function fun(...args) {
console.log(this.toString(),args);
}
let obj = {
get [Symbol.toStringTag]() {
return "自定义obj";
}
}
Reflect.apply(fun,obj,["hello","js"]); // [object 自定义obj] [ 'hello', 'js' ]
2) getPrototypeof(o), 返回对象o的原型,如果没原型则返回null。
3) set(o,name,value,receiver), 根据指定的name将对象o的属性值指定为value,如果指定了receiver参数,则将设置方法作为receiver和非o对象的设置方法调用。
class Student {
set name(val) {
console.log("设置名字:",val)
}
}
let student = new Student();
student.name = "hello student"; // 设置名字: hello student
Reflect.set(student,"name", "你好啊",(val) => {
console.log("反射设置值",val);
}); // 设置名字: 你好啊
4.2 代理对象
let proxy = new Proxy(target,handlers); // target 目标对象 handlers处理器对象。 proxy代理对象。
代理对象没有自己的状态或行为,每次对它执行某个操作,它只会把相应的操作发送给处理器对象或目标对象。(如果处理器对象上存在对应方法,代理就调用该方法,否则执行目标对象对应的方法)。
function creteCustomProxy(target) {
let handlers = {
get(target,property, receiver) {
console.log(`Handler GET target:${target} property: ${property}`);
return Reflect.get(target,property,receiver);
},
set(target,prop, value, receiver) {
console.log(`Handler SET target ${target} prop ${prop} value: ${value}`);
if (prop === 'java') throw new Error("不是JAVA");
Reflect.set(target,prop,value,receiver);
}
};
return new Proxy(target,handlers);
}
let obj = {};
let proxy = creteCustomProxy(obj);
proxy.x = "hello";
console.log(proxy.x);
proxy.java = "haha";
// Handler SET target [object Object] prop x value: hello
// Handler GET target:[object Object] property: x
// hello
// Handler SET target [object Object] prop java value: haha
// /Users/huangzaizai/Desktop/个人/代码/js-study/day4/article/s10.js:9
// if (prop === 'java') throw new Error("不是JAVA");
// ^
//
// Error: 不是JAVA
4.2.1 防御性编程
Proxy.revocable() 函数返回一个对象,包含代理对象和一个revoke()函数,一旦调用revoke(),代理立即失效。
let obj = {}
let handle = {}
let { proxy, revoke } = Proxy.revocable(obj,handle);
proxy.x = 2;
console.log(obj); // { x: 2 }
revoke();
proxy.y = 2; // 报错 TypeError: Cannot perform 'set' on a proxy that has been revoked
这个函数的用处是:如果必须向一个不受自己控制的库传一个函数,则可以给它传一个可撤销代理,在使用完这个库之后撤销代理,这样可以防止第三方库持有对你函数的引用。
相关文章:
JS元编程
如果说常规编程是写代码去操作数据,那么元编程就是写代码去操作其他代码。 1 属性的特性 JS的属性有名字和值,但每个属性也有3个关联的特性: 可写(writable)特性指定是否可修改属性的值。 可枚举(enume…...
通过Gunicorn、Supervisor和Nginx更好地运行Django
文章目录 通过runserver运行Django通过Gunicorn运行Django通过Nginx来做反向代理通过Supervisor来托管gunicorn和nginx 同步发布在个人站点:https://panzhixiang.cn 通过runserver运行Django 相信用过Django做开发的人对于python manage.py runserver 这个命令一定…...
[SQL] union all
UNION ALL 是一个用于合并多个查询结果集的操作符。它将多个 SELECT 查询的结果合并成一个结果集,并且保留所有的行,包括重复的行。 具体语法如下: SELECT column1, column2, ... FROM table1 UNION ALL SELECT column1, column2, ... FROM…...
Filebeat+Kafka+ELK日志分析架构
目录 一、zookeeper: 1. zookeeper 定义: 2. Zookeeper 工作机制: 3. Zookeeper 特点: 4. Zookeeper 数据结构: 5. Zookeeper 应用场景: 5.1 统一命名服务: 5.2 统一配置管理: 5.3 统一集群管理: 5.4 服务器动态上下线: 5.5 软负载均衡: 6. Zookeeper 选…...
RK3568驱动指南|第六篇-平台总线-第55章 初识设备树
瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…...
【ELK 使用指南 1】ELK + Filebeat 分布式日志管理平台部署
ELK和EFLK 一、前言1.1 日志分析的作用1.2 需要收集的日志1.3 完整日志系统的基本特征 二、ELK概述2.1 ELK简介2.2 为什么要用ELK?2.3 ELK的组件 三、ELK组件详解3.1 Logstash3.1.1 简介3.1.2 Logstash命令常用选项3.1.3 Logstash 的输入和输出流3.1.4 Logstash配置文件 3.2 E…...
Springboot高频应用注解
本文旨在记录开发中遇到的SpringBoot高频注解,并针对其具体应用记录。 一、LOMBOK相关注解 Slf4j 目的在于使用Log的日志功能,可以在JAVA中自动生成日志记录器!使用时在类上添加Slf4j注解后即可以在类中调用log方法如 可以 调用 log.info …...
面试总结分享:25道数据库测试题
1)什么是数据库测试? 数据库测试也称为后端测试。数据库测试分为四个不同的类别。数据完整性测试 数据有效性测试 数据库相关的性能 测试功能,程序和触发器 2)在数据库测试中,我们需要正常检查什么? 通常&a…...
和硕首次参加展OCP 峰会,将发布多项AI合作项目产品 | 百能云芯
电子代工大厂和硕联合科技宣布,将参与今年的 OCP 全球峰会 (OCP Global Summit),展示与英伟达 (NVIDIA) 合作成果,包含使用英伟达 GH200 Grace Hopper 超级芯片的 MGX AI 服务器,以及搭载 A100、L40 等服务器产品。 OCP 峰会于 10…...
FPGA基于1G/2.5G Ethernet PCS/PMA or SGMII实现 UDP 网络视频传输,提供工程和QT上位机源码加技术支持
目录 1、前言版本更新说明免责声明 2、我这里已有的以太网方案3、设计思路框架视频源选择OV5640摄像头配置及采集动态彩条UDP协议栈UDP视频数据组包UDP协议栈数据发送UDP协议栈数据缓冲IP地址、端口号的修改Tri Mode Ethernet MAC1G/2.5G Ethernet PCS/PMA or SGMIIQT上位机和源…...
小程序setData动态传递key
有些时候可能需要根据key是个变量 比如 let keyName "name" this.setData({keyName :"张三" })本来想将keyName替换为name的,但是小程序只会在data中定义一个key为keyName ,value为“张三”的一条数据。 正确写法为: let keyNam…...
boost Geometry
boost::Geometry boost作为C中最常用的第三方库,Geometry库里面拥有大量的开源算法。 函数作用get获取几何图形(通常为点)的坐标值get (with index)获取框或段的坐标值set设置几何图形(通常为点)的坐标值set (with i…...
凉鞋的 Unity 笔记 201. 第三轮循环:引入变量
201. 第三轮循环:引入变量 在这一篇,我们进行第三轮 编辑-测试 循环。 在之前我们编写了 输出 Hello Unity 的脚本,如下: using System.Collections; using System.Collections.Generic; using UnityEngine;public class FirstGameObject …...
小魔推短视频裂变工具,如何帮助实体行业降本增效?
在如今的互联网时代,大多数的实体老板都在寻找不同的宣传方法来吸引客户,现在短视频平台已经成为重中之重的获客渠道之一,而如何在这个日活用户超7亿的平台获取客户,让更多人知道自己的门店、自己的品牌,泽成为了不少老…...
VBA技术资料MF71:查找所有空格并替换为固定字符
我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。我的教程一共九套,分为初级、中级、高级三大部分。是对VBA的系统讲解,从简单的入门,到…...
c++小知识
内联函数 inline 用来替换宏函数 不能分文件编辑 在c语言中#define NULL 0在c中使用nullptr表示空指针class内存的大小计算规则使用的是内存对齐 没有成员,但是还有1个字节,我们使用这个来标记他是个类 类成员函数不存在于类中 为什么每个对象使用的…...
C#上位机序列9: 批量读写+事件广播
1. 读取配置文件及创建变量信息(点位名称,地址,数据类型(bool/short/int/float/long/double)) 2. 读任务&写任务,数据有变化时事件广播通知 using HslCommunication; using HslCommunication.Core; usi…...
ARM +FPGA GPIB IP核实现
目前在数据发生其技术上居领先的是美国的 Tektronix 公司和 Agilent 公司。 Agilent 公司的台式脉冲 / 数据发生器家族的最高时钟频率达 3GHz (定 时发生器),数据发生器 E81200 在通道数为 8CH 时数据速率为 660Mb/s, 即可以产…...
有消息称苹果Vision Pro会有廉价版
据外媒爆料,苹果公司苹果正在研发的头显产品Vision Pro,将会有廉价版。据透露,这款产品预计售价在1500美元至2500美元之间,虽然仍不算低,但较现有的Vision Pro 3499美元的起售价,还是有明显降低。 透露廉价…...
jenkins整合gerrit
背景 公司项目之前使用jenkins整合了gitlab,后面代码迁移到gerrit,所以需要修改jenkins配置。下面就简单的介绍一下jenkins如何整合gerrit。 环境 服务器:linux 环境:docker、jenkins 代码仓库:gerrit 前提 docke…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...
鸿蒙HarmonyOS 5军旗小游戏实现指南
1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发,采用DevEco Studio实现,包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...
客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践
01技术背景与业务挑战 某短视频点播企业深耕国内用户市场,但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大,传统架构已较难满足当前企业发展的需求,企业面临着三重挑战: ① 业务:国内用户访问海外服…...
