javascript 元编程之 method_missing

引言

要说元编程 ruby 中技巧太多了,今天来写的这个技术也来自于 ruby 中的灵感。

method_missing 这个在 ruby 中对象调用方法如果没有调到就会去调用这个方法。

这个功能在 javascript 中怎么实现,现在 proxy 出现了,这个就有思路了。

实现

class Base {
constructor () {
return new Proxy(this, {
get (target, property) {
if (Reflect.has(target, property)) {
return Reflect.get(target, property)
} else {
return function () {
if (target.method_missing) {
return target.method_missing(property, ...arguments)
} else {
throw new ReferenceError('Property "' + property + '" does not exist.')
}
}
}
}
})
}
}

代码解释一下, 用了 class, Proxy 的功能。

怎样使用呢?

我说一下应用场景,在前端单页面中,有很多的 ajax 接口,如果你想使用一般情况下会怎么做呢?

会先把网络库(jquery, axios) 封一层变成 http ,然后再把请求分一层,变成 request,最后对每个接口封一层,把调用方法变成一个一个的方法,放到一个文件夹中管理 api,然后在别的地方引用。

这样当然能工作。问题在于接口信息太冗余,接口的信息放在三个地方,url 中,参数中,方法名,如果有一个要改,可能三个地方都要改。

而且是要对每个函数都要做一遍这个工作。

下面举例:


// http 方法 import $ from 'jquery' window.jQuery = $ $.ajaxSetup({
cache: false,
dataType: 'json'
}) // request 方法
export function request (url, setting) {
return new Promise((resolve, reject) => {
$.ajax(url, setting)
.then(resolve)
.fail(reject)
})
} export function get (url, params) {
return request(url, {
method: 'GET',
data: params
})
} export function post (url, params) {
return request(url, {
method: 'POST',
data: params
})
} // 具体的方法
import { post } from '@/lib/http' export function getPermission (params = {}) {
return post('/passport/permission', params)
}

我们可以看到具体的方法中,函数名和 url 其实都在表达一个意思,而且如果再来接口我还要这么干。

如果20多个接口,都是这种重复代码,不应该这么干。

实现

怎么做?

上面写的 method_missing 方法上场了,我们不封方法了,直接写函数,然后委托 method_missing 方法进行统一的调用,让我们从重复的封方法中解脱出来,干点别的什么事。

import Base from './base'
import { request } from './http'
import * as _ from 'lodash' let METHOD = {
GET: ['get', 'show'],
POST: ['post', 'update', 'change', 'create', 'delete', 'remove']
} class ApiService extends Base {
constructor () {
super()
this.baseURL = '/api/web'
} method_missing (property, ...args) {
let [url, setting] = args if (_.isObject(url)) {
setting = {
data: url
} // 这里通过方法名生成 url
const url_parts = property.split('_')
const method = url_parts[0].toLowerCase() if (METHOD.GET.includes(method)) {
setting.method = 'GET'
url_parts.shift()
} else if (METHOD.POST.includes(method)) {
setting.method = 'POST'
url_parts.shift()
} else {
setting.method = 'GET'
} url = '/' + url_parts.join('/')
} return request(this.baseURL + url, setting)
}
} export default new ApiService() // 执行代码
import apiService from './api-service' // 调用,神奇的代码
apiService.get_passport_permission({
})

从执行代码来看,我并没有定义这个方法,这个方法会落到 apiserver 中的 method_missing 中去。

拿到方法名和参数列表,我就能干事情,跟据方法名去生成 url,然后参数加上,就能发请求了。

结论

这个方法在代码上如果你接口特别多的话,可以节省太多的样板代码,而且是越是通用的代码,越好,如果有特例的代码,可以加到实现 method_missing 的类中。

这样通用的代码和特例的代码都能兼顾,当然兼容性还是要考虑的。

最新文章

  1. 录像时调用MediaRecorder的start()时发生start failed: -19错误
  2. android html 图片处理类--加载富文本工具类
  3. PG sys function
  4. 拖拽碰撞效果,高级浏览器下全部搞定(ie6-8还没有搞定)
  5. C#代码配置IIS 操纵IIS
  6. 基于类和redis的监控系统开发
  7. c#开发Mongo笔记第一篇
  8. java 正则表达式例子, 查找字符串
  9. The largest prime factor(最大质因数)
  10. perl 登录某网站
  11. ListView之ArrayAdapter
  12. SqLiter
  13. python中的collections.namedtuple
  14. 201521123044 《Java程序设计》第13周学习总结
  15. 解决类似umount target is busy挂载盘卸载不掉问题
  16. Node.js实战项目学习系列(1) 初识Node.js
  17. 将webcam设置为网站favicon
  18. centos6 通过 kvm 安装 centos7
  19. vi卡死解决办法
  20. Hive HBase Integration 集成

热门文章

  1. springmvc xml文件配置中使用系统环境变量
  2. jenkins常用插件安装
  3. 2019 Unreal Open Day —— 英特尔携手 UE 助力游戏开发生态建设
  4. linux 中的命令是什么?执行命令的几种方式?如何自己创建命令?
  5. 菜鸟系列docker——docker容器(7)
  6. 并发-synchronized
  7. windows下,给golang编译的exe添加一个图标
  8. Web循环监控Java调用 / Java调用.net wcf接口
  9. linux常用终端命令(一)终端命令格式(二)文件和目录常用命令
  10. linux + qt 环境搭建