热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JavaScript反科里化this[译]_javascript技巧

本文主要讲了JavaScript中科里化和反科里化this的方法.话题来自于BrendanEich(JavaScript之父)的一个tweet
本文主要讲了Javascript中科里化和反科里化this的方法.话题来自于Brendan Eich(Javascript之父)的一个tweet.

1.反科里化(Uncurrying)this

反科里化this的意思是:把一个签名如下的方法:

obj.foo(arg1, arg2)转换成另外一个签名如下的函数:

foo(obj, arg1, arg2)想要知道这么做有什么用,我们首先得了解一下通用方法.

2.通用方法(Generic methods)

通常情况下,某个特定的方法只能在某种特定类型的对象实例上使用.但是,有一些方法如果还可以使用在其他类型的对象实例上的话,那会非常有用,例如:

代码如下:


// 实际实现的简化版本:
Array.prototype.forEach = function (callback) {
for(var i=0; iif (i in this) {
callback(this[i], i);
}
}
};


this可以看做是forEach()方法的隐含参数.满足下面这三条规则的对象都可以调用forEach()方法,都可以作为这个隐含的this:

•具有length属性: this.length
•能够通过索引访问对象元素: this[i]
•能够检查属性的存在性: i in this
arguments对象(包含了一次函数调用的所有实参)不是一个Array实例,所以它不能直接调用forEach()方法.但是你它满足调用forEach方法的三个条件.为了让该对象能够调用到forEach()方法,我们只需要让隐含的this参数作为显式参数.幸运的是,每个函数都有call()方法让我们来做件事:

代码如下:


function printArgs() {
Array.prototype.forEach.call(arguments, function (elem, index) {
console.log(index+". "+elem);
});
}


forEach.call()比forEach()方法多一个参数:它的第一个参数就是指定的this值:

代码如下:


> printArgs("a", "b")
0. a
1. b


Javascript中有几个类似的通用方法都可以以这种方式来调用,这些方法大部分来自Array.prototype.

3.反科里化this的几个用途

用例1:通过map()调用一个方法. Array.prototype.map()方法允许你在一个数组中的每个元素上调用一个函数.但如果你想调用的不是函数还是方法呢?可以利用反科里化this这么做:

代码如下:


> var toUpperCase = String.prototype.toUpperCase.uncurryThis();
> [ "foo", "bar", "baz" ].map(toUpperCase)
[ 'FOO', 'BAR', 'BAZ' ]


用例2:将一个通用方法转换成函数. 利用反科里化this可以将一个方法转换成一个用法更简单的函数.比如:

代码如下:


Array.forEach = Array.prototype.forEach.uncurryThis();
function printArgs() {
Array.forEach(arguments, function (elem, index) {
console.log(index+". "+elem);
});
}


在未来版本的ECMAScript规范建议中已经有了很多类似的数组方法.
译者注:Firefox已经实现了Array.map,Array.forEach等方法.

4.实现uncurryThis()
下面是实现uncurryThis方法的三种方式.

实现1: Brendan Eich写的

代码如下:


Function.prototype.uncurryThis = function () {
var f = this;
return function () {
var a = arguments;
return f.apply(a[0], [].slice.call(a, 1));
};
};


实现2: 调用反科里化过的函数相当于在原方法上通过调用它的call()方法来执行.我们可以通过bind()方法把这个call()方法借过来:

代码如下:


Function.prototype.uncurryThis = function () {
return this.call.bind(this);
};


实现3: 定义的标准方法最好不要依赖过多的外部方法.此外,bind()方法只在ECMAScript 5中可用.因此我们重写了上面的实现2,如下:

代码如下:


Function.prototype.uncurryThis = function () {
var f = this;
return function () {
return f.call.apply(f, arguments)
};
};


上面的代码仍然是隐式的借用了call()方法.

5.反向操作也很有用 – 科里化this
uncurryThis()的反向操作称之为curryThis().它将原函数的第一个参数转换成隐含的this参数.假如有个原函数:

代码如下:


function(self, arg) {
return self.foo + arg;
}


科里化this后成为:

代码如下:


function(arg) {
return this.foo + arg;
}


用例: 让一个方法把自己的this值传递到一个内嵌函数里.原来的写法:

代码如下:


var obj = {
method: function (arg) {
var self = this; // 让嵌套的函数访问到this
someFunction(..., function() {
self.otherMethod(arg);
});
},
otherMethod: function (arg) { ... }
}


科里化后你可以这么写:

代码如下:


var obj = {
method: function (self, arg) { // 附加参数`self`
someFunction(..., function() {
self.otherMethod(arg);
});
}.curryThis(), // 传入附加参数
otherMethod: function (arg) { ... }
}


我们把隐含的参数this转换成了显式的参数self.换句话说:我们把一个动态的this转换成了一个静态的变量self.如果this总是作为一个显式的参数,则Javascript会变的更简单点.

实现curryThis():

代码如下:


Function.prototype.curryThis = function () {
var f = this;
return function () {
var a = Array.prototype.slice.call(arguments);
a.unshift(this);
return f.apply(null, a);
};
};

6.如果你不想扩展函数原型

上面实现的方法都是加在了内置构造函数Function()的原型上.你应该可以轻松的将它们重写为独立的函数.

代码如下:


function uncurryThis(f) {
return function () {
return f.call.apply(f, arguments)
};
}
function curryThis(f) {
return function () {
var a = Array.prototype.slice.call(arguments);
a.unshift(this);
return f.apply(null, a);
};
}

7.在uncurryThis()安全的使用在已经存在的不信任的代码中

Mark Miller把uncurryThis()作为例子讲解了“安全的元编程”:

译者注:科里化this就是把函数的第一个参数转换成方法中的this.反科里化this就是把方法中的this转换成函数的第一个参数.

推荐阅读
  • 本文整理了常用的CSS属性及用法,包括背景属性、边框属性、尺寸属性、可伸缩框属性、字体属性和文本属性等,方便开发者查阅和使用。 ... [详细]
  • Apache Shiro 身份验证绕过漏洞 (CVE202011989) 详细解析及防范措施
    本文详细解析了Apache Shiro 身份验证绕过漏洞 (CVE202011989) 的原理和影响,并提供了相应的防范措施。Apache Shiro 是一个强大且易用的Java安全框架,常用于执行身份验证、授权、密码和会话管理。在Apache Shiro 1.5.3之前的版本中,与Spring控制器一起使用时,存在特制请求可能导致身份验证绕过的漏洞。本文还介绍了该漏洞的具体细节,并给出了防范该漏洞的建议措施。 ... [详细]
  • JavaWeb介绍概念JavaWeb,是用Java技术来解决相关web互联网领域的技术总和。web包括:web服务器和web客户端两部分。Java在客户端的应用有javaapplet,不过使 ... [详细]
  • 校内无法访问IEEE等部分数据库的解决方案
    解决了校内无法访问IE ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 本文介绍了新款奇骏的两个让人上瘾的功能,分别是智能互联系统和BOSE音响。通过对新款奇骏的配置和功能进行评测,探讨了这两个新增功能的使用体验和优势。此外,还介绍了新款奇骏的其他配置和改进,如增加的座椅和驾驶辅助系统,以及内饰的舒适性提升。对于喜欢音响的消费者来说,BOSE音响的升级也是一个亮点。最后,文章提到了BOSE音响的数字还原能力,以及7座版无法配备BOSE音响的原因。 ... [详细]
  • 图解BOM与DOM的区别与联系
    区别BOM(BrowserObjectModel)BOM即浏览器对象模型,BOM没有相关标准,BOM的最核心对象是window对象。window对象既为javascript访问浏览 ... [详细]
  • FileReader详解与实例---读取并显示图像文件
    我们曾经在《HTML5中File对象初探》中,使用到了FileReader,在那篇文章中,它被用来将一个文件读取为二进制字符串,并通过xhr发送到后端形成交互。作为FileAPI的一部 ... [详细]
  • 前端~javascript~webAPI/文档对象模型Dom/Dom树/事件机制/操作元素/实战案例:实现网页计数器
    文章目录WebAPI简介DomDom树获取Dom元素事件事件三要素操作dom元素innerHTMLinnerText实战案例:实现网页计数器WebAPI简介什么是AP ... [详细]
  • div#container{width:600px;height:600px;background-color:#00 ... [详细]
author-avatar
Yuki_沐1824355667
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有