浅谈es6中的元编程


Posted in Javascript onDecember 01, 2020

何为元编程?

「编写能改变语言语法特性或者运行时特性的程序」。换言之,一种语言本来做不到的事情,通过你编程来修改它,使得它可以做到了,这就是元编程。

meta-programming元编程中的 元 的概念可以理解为 程序 本身。”元编程能让你拥有可以扩展程序自身能力

举个例子:

if (a == 1 && a == 2 && a == 3) {
  console.log("done");
}

怎样才能让这个条件满足,输出done。按照正常的逻辑是无法完成的,毕竟一个值不可能同时满足等于1、2、3

这是就可以用到元编程来改变这个不可能

let a = {
  [Symbol.toPrimitive]: ((i) => () => ++i)(0)
}

if (a == 1 && a == 2 && a == 3) {
  console.log("done");
}
// done

Symbol.toPrimitive在对象转换为原始值的时候会被调用,初始值为1,调用一次+1,就可以满足a == 1 && a == 2 && a == 3,同时Symbol.toPrimitive也可以接受一个参数hint,hint的取值为number、string、default

let obj = {
  [Symbol.toPrimitive](hint) {
    switch (hint) {
      case "number":
        return 123;
      case "string":
        return "str";
      case "default":
        return "default";
    }
  }
}
console.log(1-obj); // -122
console.log(1+obj); // 1default
console.log(`${obj}`); // str

还有哪些元编程?

proxy

es5的Object.defineProperty()方法的es6升级版,用于自定义的对象的行为

let leon = {
  age: 30
}
const validator = {
  get: function(target, key){
    // 若没这个属性返回37
    return key in target ? target[key] : 37;
  },
  set(target,key,value){
    if(typeof value!="number" || Number.isNaN(value)){
      throw new Error("年龄得是数字");
    }
  }
}
const proxy = new Proxy(leon,validator);
console.log(proxy.name);
// 37
proxy.age = "hi";
// Error: 年龄得是数字

reflect-metadata

你可以通过装饰器来给类添加一些自定义的信息。然后通过反射将这些信息提取出来。当然你也可以通过反射来添加这些信息

require("reflect-metadata")
class C {
  // @Reflect.metadata(metadataKey, metadataValue)
  method() {
  }
}
Reflect.defineMetadata("name", "jix", C.prototype, "method");

let metadataValue = Reflect.getMetadata("name", C.prototype, "method");
console.log(metadataValue);
// jix

应用

拓展数组索引访问

负索引访问,使array[-N] 与 array[array.length - N] 相同

let array = [1, 2, 3];

array = new Proxy(array, {
 get(target, prop, receiver) {
  if (prop < 0) {
   console.log(prop, 'prop')
   prop = +prop + target.length;
  }
  return Reflect.get(target, prop, receiver);
 }
});


console.log(array[-1]); // 3
console.log(array[-2]); // 2

数据劫持

let handlers = Symbol('handlers');

function makeObservable(target) {
 // 初始化存储 handler 的数组
 target[handlers] = [];

 // 存储 handler 函数到数组中以便于未来调用
 target.observe = function(handler) {
  this[handlers].push(handler);
 };

 // 创建代理以处理更改
 return new Proxy(target, {
  set(target, property, value, receiver) {
   // 转发写入操作到目标对象
   let success = Reflect.set(...arguments);
   // 如果设置属性的时候没有报错
   if (success) {
    // 调用所有 handler
    target[handlers].forEach(handler => handler(property, value));
   }
   return success;
  }
 });
}

let user = {};

user = makeObservable(user);

user.observe((key, value) => {
 console.log(`SET ${key}=${value}`);
});

user.name = "John";
// SET name=John

到此这篇关于浅谈es6中的元编程的文章就介绍到这了,更多相关es6 元编程内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木! 

Javascript 相关文章推荐
Prototype使用指南之selector.js说明
Oct 26 Javascript
javascript oop开发滑动(slide)菜单控件
Aug 25 Javascript
jQuery实现单行文字间歇向上滚动源代码
Jun 02 Javascript
JS实现仿京东淘宝竖排二级导航
Dec 08 Javascript
用JS生成UUID的方法实例
Mar 30 Javascript
手机端图片缩放旋转全屏查看PhotoSwipe.js插件实现
Aug 25 Javascript
js实现鼠标左右移动,图片也跟着移动效果
Jan 25 Javascript
Vue-resource实现ajax请求和跨域请求示例
Feb 23 Javascript
Javascript迭代、递推、穷举、递归常用算法实例讲解
Feb 01 Javascript
layui table去掉右侧滑动条的实现方法
Sep 05 Javascript
Vue中import from的来源及省略后缀与加载文件夹问题
Feb 09 Javascript
JavaScript实现鼠标经过表格某行时此行变色
Nov 20 Javascript
Vue.js桌面端自定义滚动条组件之美化滚动条VScroll
Dec 01 #Vue.js
微信小程序轮播图swiper代码详解
Dec 01 #Javascript
利用JavaScript模拟京东按键输入功能
Dec 01 #Javascript
layui使用及简单的三级联动实现教程
Dec 01 #Javascript
vue开发chrome插件,实现获取界面数据和保存到数据库功能
Dec 01 #Vue.js
编写v-for循环的技巧汇总
Dec 01 #Javascript
jquery实现拖拽添加元素功能
Dec 01 #jQuery
You might like
Ajax PHP分页演示
2007/01/02 PHP
PHP include任意文件或URL介绍
2014/04/29 PHP
PHP实现多维数组转字符串和多维数组转一维数组的方法
2015/08/08 PHP
PHP设计模式入门之迭代器模式原理与实现方法分析
2020/04/26 PHP
js身份证验证超强脚本
2008/10/26 Javascript
js拖动div 当鼠标移动时整个div也相应的移动
2013/11/21 Javascript
Jquery中&quot;$(document).ready(function(){ })&quot;函数的使用详解
2013/12/30 Javascript
简单实现限制uploadify上传个数
2015/11/16 Javascript
详解nodejs 文本操作模块-fs模块(一)
2016/12/22 NodeJs
AngularJS使用带属性值的ng-app指令实现自定义模块自动加载的方法
2017/01/04 Javascript
原生js实现回复评论功能
2017/01/18 Javascript
jQuery元素选择器实例代码
2017/02/06 Javascript
原生javascript实现的全屏滚动功能示例
2017/09/19 Javascript
详解JSON Web Token 入门教程
2018/07/30 Javascript
对vux点击事件的优化详解
2018/08/28 Javascript
微信小程序实现导航栏和内容上下联动功能代码
2020/06/29 Javascript
[48:29]2018DOTA2亚洲邀请赛3月30日 小组赛A组 LGD VS KG
2018/03/31 DOTA
使用Python标准库中的wave模块绘制乐谱的简单教程
2015/03/30 Python
python使用BeautifulSoup分页网页中超链接的方法
2015/04/04 Python
详解Python中列表和元祖的使用方法
2015/04/25 Python
python虚拟环境的安装配置图文教程
2017/10/20 Python
python二维列表一维列表的互相转换实例
2018/07/02 Python
Linux 修改Python命令的方法示例
2018/12/03 Python
celery4+django2定时任务的实现代码
2018/12/23 Python
使用Python创建简单的HTTP服务器的方法步骤
2019/04/26 Python
Django发送邮件和itsdangerous模块的配合使用解析
2019/08/10 Python
Pytorch 中的optimizer使用说明
2021/03/03 Python
eBay英国购物网站:eBay.co.uk
2019/06/19 全球购物
介绍下java.util.Arrays类
2012/10/16 面试题
毕业生自我鉴定
2013/11/05 职场文书
函授教育个人学习的自我评价
2013/12/31 职场文书
个人欠条范本
2015/07/03 职场文书
党校培训学习心得体会
2016/01/06 职场文书
python 办公自动化——基于pyqt5和openpyxl统计符合要求的名单
2021/05/25 Python
教你怎么用python selenium实现自动化测试
2021/05/27 Python
MySQL 中如何归档数据的实现方法
2022/03/16 SQL Server