javascript 元编程之 method_missing
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 的类中。
这样通用的代码和特例的代码都能兼顾,当然兼容性还是要考虑的。
javascript 元编程之 method_missing的更多相关文章
- Javascript元编程之Annotation
语言的自由度 自由度这个概念在不同领域有不同的定义,我们借鉴数学中构成一个空间的维数来表达其自由度的做法,在此指的是:解决同一个问题彼此不相关的设计方法学数量. 例如,解决一个比如商品打折的问题,如何 ...
- Javascript异步编程之setTimeout与setInterval详解分析(一)
Javascript异步编程之setTimeout与setInterval 在谈到异步编程时,本人最主要会从以下三个方面来总结异步编程(注意:特别解释:是总结,本人也是菜鸟,所以总结不好的,请各位大牛 ...
- 【转】Javascript异步编程之setTimeout与setInterval
Javascript异步编程之setTimeout与setInterval 转自:http://www.tuicool.com/articles/Ebueua 在谈到异步编程时,本人最主要会从以下三个 ...
- JavaScript模块化编程之AMD - requireJS基础使用
JavaScript模块化编程之AMD requireJS基础使用 标签(空格分隔): JavaScript 参考文章 AMD规范 AMD是"Asynchronous Module Defi ...
- JavaScript模块化编程之require.js与sea.js
为什么要模块化:当今,网站以不再是一个简单的页面,JavaScript也不再是做一些简单的脚本验证,随着WEB.20时代到来,前端工程师面临的必将是越来越庞大的JavaScript代码,越来越复杂的内 ...
- 我也来谈javascript高级编程之:javascript函数编译过程
前言 题目有点大,其实也就是手痒...跟大家来扯一下javascript编译过程. 那么到底什么是“编译”呢 这个...本人文笔太差,我还是直接举例子吧. 相信玩过js童鞋应该都看过下面这样一个面试题 ...
- Javascript模块化编程之Why
说到模块化编程,大家比较容易想到Java, C++等语言,感觉这事和Javascript沾不上一丁点边.虽说Javascript看上去好像同Java有莫大的关系,但那也只是一厢情愿,不过是挂羊头卖狗肉 ...
- JavaScript模块化编程之AMD
简单的说一下AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义".它采用异步方式加载模块,模块的加载不影响它 ...
- Javascript模块化编程之CommonJS,AMD,CMD,UMD模块加载规范详解
JavaSript模块化 在了解AMD,CMD规范前,还是需要先来简单地了解下什么是模块化,模块化开发? 模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问 题进行系 ...
随机推荐
- vagrant虚拟机共享目录在windows宿主下的禁忌
问题背景 宿主环境:Windows10 开发环境:vagrant(ubuntu) 操作目录:synced_folder (共享目录 ) 执行命令:npm install 错误信息: npm ERR! ...
- React Native解决安卓图片被挤压
Bug如下图所示: iOS显示正常,而安卓出现图片被挤压上去. 最后的解决方法: 比如你的 图片 是 750 x 513 那么 你设置样式的时候 width 为 屏幕的宽 ,高度为 屏幕的 宽 / ( ...
- 一篇文章搞懂android存储目录结构
前言 前两天因为开发一个app更新的功能,我将从服务器下载的apk文件放在了内部存储目录(测试手机为小米,路径为:data/user/0/packagename/files)下面,然后安装的时候一直安 ...
- 写linux脚本你怎么能不知道位置参数!?
在写shell脚本的时候,我们经常会手动设置参数,然后对我们的输入的这些参数进行处理和分析,那么这个东东到底值怎么使用的呢? 1.$n $0代表命令本身,$1-9代表接受的第1-9个参数,10以上需要 ...
- SSM项目模板
项目一:恒德物流平台(SSM) ◎开发周期:3个月 开发模式:团队4个人 ◎开发环境:jdk1.8.tomcat8.5 开发工具:IDE ...
- Django组件-admin
一. admin组件的使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.你可以在项目的 settings.py 中的 INST ...
- 【VS开发】recv函数函数返回值说明(特别有利于工程调试)
recv函数 int recv( SOCKET s, char FAR *buf, int len, int flags); 不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据. ...
- 【机器学习】数据处理中白化Whitening的作用图解分析
之前在看斯坦福教程中whiteining这一章时,由于原始图像相邻像素值具有高度相关性,所以图像数据信息冗余,对于白化的作用的描述主要有两个方面:1,减少特征之间的相关性:2,特征具有相同的方差(协方 ...
- Prometheus + Grafana 监控 Redis
Prometheus安装 .linux-amd64.tar.gz .linux-amd64. cd /prometheus # Start Prometheus. # By default, Prom ...
- windows登录密码忘记了怎么办?
利用PE工具进行进行修改密码或者重置系统密码,正对于服务器也同样试用 目前U启动制作效果还不错,黑鲨一键装机,以及老毛桃我觉得还是算了,U深度也不错 经过这么久,小编也把该测试的测试了,,小编比较懒, ...