原文: http://dojotoolkit.org/documentation/tutorials/1.10/hitch/index.html

版本: Dojo 1.10

为了更好地使用JavaScript原生函数,dojo/_base/lang模块提供了很多非常有用的方法。这里,我们来学习JavaScript函数(Function)对象基础,及如何使用lang.hitch来绑定函数的上下文。在此基础上,学习如何使用lang.partial来绑定函数的特定参数,及如何使用lang.hitch实现这两个操作。

在开始学习之前,你需要对Dojo Toolkit基础知识有一定的了解,如dojo/query, Dojo's Array helpers等。

在理解如何及何时使用lang.hitch和lang.partial之前,我们需要知道它们解决了什么问题。JavaScript中最容易被误解的一个概念是:this是什么?通常,在面向对象编程中,当一个对象的方法被调用时,this就指向这个对象。然而在JavaScript中并不是这样,为了更好的理解它,我们要先理解执行上下文(execution context)概念。

JavaScript中的执行上下文

在JavaScript中,无论何时调用一个函数,就会创建它的执行上下文。这个上下文的创建步骤是:

1)创建arguments对象;

2)创建函数的scrope对象;

3)初始化函数的变量;

4)创建this属性。

这里的this属性是开发者最容易迷惑的地方,它就是调用该函数的上下文或scope的对象一个引用。理解这一点是理解JavaScript如何工作的关键,因为JavaScript中,一个函数执行的真正上下文是在函数被调用时才能决定的。

下面是一个例子: 假如我们有一个对象,对象中的一个方法将被用作文档中的某些节点的事件处理函数。

 // Require the query resource, and wait until the DOM is ready
require(['dojo/query', 'dojo/domReady!'], function(query) {
var myObject = {
foo: "bar",
myHandler: function(e) {
// This is very contrived but will do.
alert("The value of 'foo' is " + this.foo);
}
}; // later on in the script:
query('.myNodes').forEach(function(node) {
node.onclick = myObject.myHandler;
});
});

当点击了具有‘myNodes’类的任何一个DOM节点时,你可能会认为上面的函数定义会弹出一个JavaScript警示框提示“The value of 'foo' is bar”,然而,由于我们设定myObject.myHandler为节点点击的事件处理器,我们将会得到“The value of 'foo' is undefined”提示信息。看看原因:

node.onclick =  myObject.myHandler; 这个表达式myObject.myHandler调用了myHandler函数,事实上,myHandler函数是在myObject对象中定义这一事实已经被忽视了,现在node.onclick是myHandler函数的引用,注意这里只是myHandler这个函数,而并不是myObject的上下文。DOM事件处理器运行的上下文是触发这个事件的节点,也就是说,不考虑它是在哪及如何定义的,这个函数如同是该节点的一个方法一样被执行,结果就是在执行时myHandler函数内部的this值是当前触发事件的节点。

注意:如果觉得这很迷惑,牢记一点:根本原因是因为如同其它非基本类型,Function对象是引用传递,而不是值传递。

用.apply和.call方法改变执行上下文

由于JavaScript函数执行上下文是在函数被调用时决定的,它提供了一种在执行时通过Function.apply和Function.call来改变上下文(即this)的方法。很简单,两个方法均允许传递一个对象作为执行函数的上下文。例如,如果你想保证上面例子的handler是在myObject上下文中执行的,可以使用Function.call方法来包装我们的引用,如下:

 query('.myNodes').forEach(function(node) {
node.onclick = function(e) {
myObject.myHandler.call(myObject, e);
}
});

在大多数情况下,会使用Function.apply方法,并从外部函数传递arguments对象。然而,当一个函数的参数已知时,推荐使用call方法,因为当JavaScript解释器不需要直接访问arguments对象时,会获得稍微高的性能。

用lang.hitch绑定执行上下文

Dojo Toolkit提供了一种简便的方法lang.hitch来绑定函数的上下文,简单来说,lang,hitch创建了一个Function对象,绑定给了一个特定的上下文,这样就可以实现安全地调用函数,而不需要担心函数上下文的变化。下面是一个例子:

 // `foo` is intentionally global
var foo = "bar";
require(['dojo/_base/lang'], function(lang) {
var myFunction = function() {
return this.foo;
};
var myObject = {foo: 'baz'}; // later on in your application
var boundFunction = lang.hitch(myObject, myFunction); // test
myFunction(); // "bar"
boundFunction(); // "baz"
myFunction(); // "bar"
});

lang.hitch确保了一个特定函数,绑定了一个特定执行上下文,调用时不再需要考虑执行时上下文的变化。

arguments对象

arguments对象是一个类数组对象,保存了传递给当前函数的参数列表。另外,在创建上下文时,该对象的任何命名变量已被创建,因此,这些值可以在函数内部使用,如同当前函数自身的变量一样。记住,arguments对象并不是一个真正的Array对象,尽管它与Array对象有许多相似的地方,但它是只读的,也就意味着Array对象的其他一些方法不能对arguments对象使用(如Array.prototype.slice等)。

当定义了一个函数时,函数的签名就固定下来了,不能通过除非重新定义该函数的其他任何方法增加或删除命名参数。这样也就带来了一个问题,尤其是当你需要使用一个函数签名,而不去真正复制或重写原始函数,Dojo Toolkit提供了一个简单的方法来实现这个功能——lang.partial方法。

用lang.partial改变函数的参数列表

经常会遇到的一个问题是,一个函数定义了多个参数,但是有时我们只需要部分参数。例如,假如我们有一个函数有4个参数(取自dojo/data):

 var putValue = function(store, item, attr, value) {
return store.setValue(item, attr, value);
}

但是,可能在项目的其它地方有一个类似的定义,只有3个参数:

 someObject.setValueHandler = function(item, attr, value) {
// placeholder function to be overriden
};

用lang.partial,你可以创建一个新的预先设置好参数值的函数,在上面的例子中,可以通过预先设定好store的值,然后将someObject.setValueHandler设置为部分函数的引用,如下:

 // assuming we have a dojo/data store called "myStore"

 // our function
var putValue = function(store, item, attr, value) {
return store.setValue(item, attr, value);
} // ...
// their function signature
someObject.setValueHandler = function(item, attr, value) {
// placeholder function to be overriden
}; // ...
// our solution using lang.partial
someObject.setValueHandler = lang.partial(putValue, myStore); // ...
// somewhere in the application when setValueHandler is invoked,
// our putValue function will already have the "store" arg
// set to a reference to "myStore"
someObject.setValueHandler(someItem, "foo", "bar");

对上面的解释:

1. 首先定义了一个具有4个参数的函数;

2. 发现setValueHandler函数只需要3个参数,并且我们不可以修改;

3. 我们在putValue基础上创建了一个新的函数,并且putValue的第一个参数store的值被初始设定为myStore;

4. 新的部分函数被调用时只传递了3个参数,但是此时部分函数的第一个参数的值已经被设定为myStore.

需要注意的是,不像lang.hitch方法,lang.partial并不会预先设定返回部分函数的执行上下文,换句话说,根据你使用新部分函数的不同,this的值可能有变化。

在使用lang.partial时,将函数的一个参数代表执行上下文,你可以通过设定一个对象的引用作为对象的执行上下文,从而可以同时获得二者的优势。

结合hitch和partial的优势

如果你想同时具有hitch和partial的优势,lang.hitch可以同时具有二者,你可以在上下文和方法名后添加任意多个值,lang.hitch会用预定的上下文和预先设定的参数值来创建新的函数。如下:

 someObject.setValueHandler = lang.hitch(someObject, putValue, myStore);

 // ...
// later on in the application, the setHandler is invoked
// again -- this time in the context of someObject
someObject.setValueHandler(someItem, 'foo', 'bar');

hitch和partial是了解函数式编程的基础,Dojo Toolkit中通过dojox/lang/functional命名空间提供了很多函数式编程技巧,推荐看一看。

总结

这里我们回顾了JavaScript Function对象——包括函数的调用过程。然后引入了lang.hitch,允许你去绑定一个函数的执行上下文,在些基础上,我了学习了如何使用lang.partial预设一个函数的参数值,最后介绍了如何使用lang.hitch同时绑定上下文和参数值。

由于lang.hitch允许预先绑定函数执行上下文,因此它在事件驱动的编程技术(或者基于回调的编程)中非常有用。

Dojo 学习笔记 之 Dojo hitch&partial的更多相关文章

  1. dojo 学习笔记之dojo.query - query(id) 与query(class)的差别

    考虑这个样例:动态创建一个页面的时候,用new listtem()生成多个listitem, 且每一个listitem中都生成一个按钮button. 假设想要给每一个按钮都绑定一个click事件,用d ...

  2. dojo 学习笔记

    1  因为Dijit包括了一系列的UI组件,他绑定了4个支持的主题:nihilo, soria, tundra 和claro.每个主题包括了一系列的图片和CSS文件来控制组件的外观.CSS文件必须显示 ...

  3. Elasticsearch学习笔记(九)partial update

    一.什么是partial update? PUT /index/type/id,创建文档&替换文档,就是一样的语法 一般对应到应用程序中,每次的执行流程基本是这样的: (1)应用程序先发起一个 ...

  4. dojo学习教程

    Dojo 作为最著名的 Ajax 开源项目之一,不仅让 Web 程序员可以免费获得和使用其框架进行 Web 应用的开发,更吸引了大量的开发者对其不断的扩充,开发新的组件.DojoX 就是在这样的开发社 ...

  5. 【总结整理】dojo学习

    Dojo Toolkit 的特性可以分到 4 个不同部分.这种划分使得开发人员可以将库大小保持到最小,确保应用程序性能不受大量 JavaScript 库下载的影响.例如,如果您只需要 Ajax 支持性 ...

  6. dojo框架笔记

    一.模块定义 1.定义只含值对,没有任何依赖的模块(moudle1.js) define({ color: "black", size: "unisize" } ...

  7. dojo学习(一)入门

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  8. ArcGIS JS 学习笔记1 用ArcGIS JS 实现仿百度地图的距离量测和面积量测

    一.开篇 在博客注册了三年,今天才决定写第一篇博客,警告自己不要懒!!! 二.关于ArcGIS JS 版本选择 在写这篇博客时ArcGIS JS 4.0正式版已经发布.它和3.x版本的不同是,Map不 ...

  9. CSS3与页面布局学习笔记(八)——浏览器兼容性问题与前端性能优化方案

    一.浏览器兼容 1.1.概要 世界上没有任何一个浏览器是一样的,同样的代码在不一样的浏览器上运行就存在兼容性问题.不同浏览器其内核亦不尽相同,相同内核的版本不同,相同版本的内核浏览器品牌不一样,各种运 ...

随机推荐

  1. 在SQLSERVER中创建聚集索引

    CREATE CLUSTERED INDEX CLUSTER_id ON TABLE_name(ID)------批量

  2. STP-6-快速生成树协议-新端口角色,状态和类型以及新链路类型

      IEEE 802.1w快速生成树协议(RSTP)增强了802.1D标准,在设计合理的网络中收敛时间远少于1秒.   端口状态从5个减少到3个 丢弃状态是在端口刚启用时的默认状态,边界端口除外,它的 ...

  3. 那些年坑爹的JS题目

    真是让人疑惑的基础.又是一堆奇怪的题目. 题目一. 应该是关于作用域的 function test(n) { this.x = n; return this; } var x = test(1); v ...

  4. asp:FileUpload 控件上传多文件

    <asp:FileUpload runat="server" ID="imgUpload" AllowMultiple="true" ...

  5. 17.JavaMail

    1.电子邮件 电子邮件是目前网络上使用最多的服务,电子邮件的应用越来越广泛正常的通信往来账号注册时,找回密码时等一般发送的邮件主要可以分解成2大部分一部分是发信人.接信人.主题等邮件标头另外一部分是邮 ...

  6. webAPI过滤器添加参数签名

    项目需求: 接口对安卓和IOS开发接口,需要房子用户窜改数据请求接口.添加sign签名校验参数. 代码如下:加上特性标签就可以控制部分接口验证 public class SignAuthorizeFi ...

  7. bios-----> grub

    系统有两块硬盘, 第一块安装的win7, 第二块安装ubuntu 默认从sda加载grub 如果在bios页面选择从sdb启动,会找不到grub 进入原来的sda系统,  grub-install / ...

  8. connect to 10.104.11.128 port 9999 (tcp) failed: No route to host

    问题: iptables当找到匹配的规则时,就会执行相应的动作,而不会向下继续匹配. 可以看到https没有添加,匹配不到规则,所以就会包错 解决方法: iptables -I INPUT -p tc ...

  9. js apply和call

    apply()和call()这两个方法的作用是一样的,都是在特定作用域中调用函数,等于设置函数体内this对象的只,以扩充函数赖以运行的作用域 apply:方法能劫持另外一个对象的方法,继承另外一个对 ...

  10. SpringMVC---彻底解决/和/*的问题!到底该用哪一个?

    出处: https://blog.csdn.net/sinat_33921105/article/details/81951156 在web开发中我们经常会遇到/和/*的问题,有的时候稍不注意就容易忘 ...