Dojo学习笔记(七):Making Functions with hitch and partial

简介:

    dojo/_base/lang包含两个有用的方法:lang.hitch和lang.partial。lang.hitch主要负责修改this运行上下文,lang.partial主要负责修改函数参数个数,进行函数签名。

1、JavaScript 中的运行上下文(execution contexts)

    在JavaScript中,当一个函数被调用,一个运行上下文就被创建出来。上下文的创建经过如下阶段:

    (1)arguments 参数对象的创建;

    (2)函数作用域 scope 的创建;

    (3)函数中变量 Variables 的实例化;

    (4)this 属性(指向上下文 context 自身) 的创建。

    this 属性是绝大多数开发者都会混淆的地方;它其实就是一个指向函数调用时作为上下文context(或叫作用域 scope)的对象的引用,在 JavaScript 中,函数执行时的实际上下文,是在函数被调用时才决定的。

    作用域 (scope),它就是个对象,既可以作为方法函数调用执行时的空间,也可以作为方法函数、属性等的定义空间。后面会讲到词法作用域(lexical scope),可以认为为这是 JavaScript 中真正的作用域,词法作用域使用了闭包技术closures。 

    函数调用时的作用域(scope) ,在JavaScript中称为运行上下文(execution context)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<!DOCTYPE html>
<html>
<head>
     <meta charset= "UTF-8" >
     <title>dojoConfig</title>
     <style type= "text/css" >
         .myNode {
             border: 1px solid # 999 ;
             margin:  0 .5em;
             padding:  0 .5em;
             background-color: #ccc;
             float: left;
         }
     </style>
     <script src= "dojo/dojo.js" ></script>
     <script>
         // Retrieve the dependencies
         require([ "dojo/query" "dojo/dom-construct" "dojo/domReady!" ],
                 function (query, domConstruct) {
                     function  log(msg){
                         var  c = document.getElementById( "console" );
                         if (!c){
                             c = domConstruct.create( "div" , {
                                 id:  "console"
                             }, document.body);
                         }
                         c.innerHTML +=  "<div>"  + msg +  "</div>" ;
                     }
                     var  myObject = {
                         foo:  "bar" ,
                         myHandler:  function (evt){
                             //still contrived!
                             //假设evt为事件对象:W3C标准中,使用evt.target,而IE为evt.srcElement
                             log( "The value of foo is "  this .foo +  ", from "  + (evt && evt.target ? evt.target.id : window.event.srcElement.id));
                         }
                     };
                     var  container = document.getElementById( "nodeContainer" );
                     for ( var  i= 0 ; i< 5 ; i++){
                         domConstruct.create( "div" , {
                             id:  "node-"  + (i+ 1 ),
                             className:  "myNode" ,
                             innerHTML:  "Fake button "  + (i+ 1 )
                         }, container);
                     }
                     query( ".myNode" ).forEach( function (node){
                         node.onclick = myObject.myHandler;
                     });
                 });
     </script>
</head>
<body>
<div id= "nodeContainer" >
</div>
</body>
</html>

输出结果:

The value of foo is undefined, from node-1

The value of foo is undefined, from node-2

The value of foo is undefined, from node-3

分析原因:

    期望的结果是显示显示"The value of 'foo' is bar",但我们得到信息:The value of 'foo' is undefined。

    (1)node.onclick = myObject.myHandler

    在这里 myObject.myHandler 经过解析,变成了函数 myHandler,仅仅是函数而已。而 myHandler 做为 myObject 的方法的这一事实被完全舍弃了。(将 myObject.myHandler 赋值给 onclick ,  context 什么事儿,它才不管这个函数在哪定义,他完全将这个函数同对象本身剥离了。)

    (2)如果你依然困惑,只需要记住在 JavaScript中 Functions objects同其他非原始类型一样,是引用传递,而非值传递。在我们上面的例子中,我们不过将 onclick  设置为一个直接指向 myObject.myHandler的引用。

    使用.apply和.call切换运行上下文execution contexts

1
2
3
4
5
query( ".myNode" ).forEach( function (node){
       node.onclick =  function (evt){
       myObject.myHandler.call(myObject,evt);
       };
});

    将触发绑定事件代码修改成如上内容,就可得到想要的结果。

(1)使用lang.hitch绑定运行上下文execution context

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<!DOCTYPE html>
<html>
<head>
     <meta charset= "UTF-8" >
     <title>dojoConfig</title>
     <style type= "text/css" >
         .myNode {
             border: 1px solid # 999 ;
             margin:  0 .5em;
             padding:  0 .5em;
             background-color: #ccc;
             float: left;
         }
     </style>
     <script src= "dojo/dojo.js" ></script>
     <script>
         // Retrieve the dependencies
         require([ "dojo/_base/lang" , "dojo/query" "dojo/dom-construct" "dojo/domReady!" ],
                 function (lang,query, domConstruct) {
                     function  log(msg){
                         var  c = document.getElementById( "console" );
                         if (!c){
                             c = domConstruct.create( "div" , {
                                 id:  "console"
                             }, document.body);
                         }
                         c.innerHTML +=  "<div>"  + msg +  "</div>" ;
                     }
                     var  myObject = {
                         foo:  "bar" ,
                         myHandler:  function (evt){
                             //still contrived!
                             log( "The value of foo is "  this .foo +  ", from "  + (evt && evt.target ? evt.target.id : window.event.srcElement.id));
                         }
                     };
                     var  container = document.getElementById( "nodeContainer" );
                     for ( var  i= 0 ; i< 5 ; i++){
                         domConstruct.create( "div" , {
                             id:  "node-"  + (i+ 1 ),
                             className:  "myNode" ,
                             innerHTML:  "Fake button "  + (i+ 1 )
                         }, container);
                     }
                     query( ".myNode" ).forEach( function (node){
                         node.onclick = lang.hitch(myObject, myObject.myHandler);
                     });
                 });
     </script>
</head>
<body>
<div id= "nodeContainer" >
</div>
</body>
</html>

说明:

lang.hitch可以指定函数的上下文,关键代码:

1
2
3
query( ".myNode" ).forEach( function (node){
      node.onclick = lang.hitch(myObject, myObject.myHandler);
});

(2)参数对象The arguments object

    arguments object 并非一个真正的JavaScript的Array object;尽管某些方面同数组类似(如采用数字下标索引,包含 length 属性等),但其是只读的,因此某些 Array 方法对其无效(如 Array.prototype.slice)。

(3)使用lang.partial修改函数签名function signatures

1
2
3
4
query( ".myNode" ).forEach( function (node){
      //don't forget: method first, fixed arguments second!
      node.onclick = lang.partial(myO bject.myHandler, myObject);
});

 (4)将 hitch和partial 的优点整合在一起

    是不是很想把 htich 的优点(强制运行上下文)和partial的优点(预置参数)整合在一起?好吧,lang.hitch进一步增强可以完成以上两种工作:你可以在context和method 两个参数后,再添加任意数量的参数,lang.hitch 将会绑定上下文,预置参数,生成新的函数。


    备注:hitch 和 partial 是通往函数式编程的入口(参考: functional programming);Dojo Toolkit  在 dojox/lang/functional 下提供了很多函数式编程技术东西,建议你有空看看。




    dojo/_base/lang包含两个有用的方法:lang.hitch和lang.partial。lang.hitch主要负责修改this运行上下文,lang.partial主要负责修改函数参数个数,进行函数签名。

1、JavaScript 中的运行上下文(execution contexts)

    在JavaScript中,当一个函数被调用,一个运行上下文就被创建出来。上下文的创建经过如下阶段:

    (1)arguments 参数对象的创建;

    (2)函数作用域 scope 的创建;

    (3)函数中变量 Variables 的实例化;

    (4)this 属性(指向上下文 context 自身) 的创建。

    this 属性是绝大多数开发者都会混淆的地方;它其实就是一个指向函数调用时作为上下文context(或叫作用域 scope)的对象的引用,在 JavaScript 中,函数执行时的实际上下文,是在函数被调用时才决定的。

    作用域 (scope),它就是个对象,既可以作为方法函数调用执行时的空间,也可以作为方法函数、属性等的定义空间。后面会讲到词法作用域(lexical scope),可以认为为这是 JavaScript 中真正的作用域,词法作用域使用了闭包技术closures。 

    函数调用时的作用域(scope) ,在JavaScript中称为运行上下文(execution context)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<!DOCTYPE html>
<html>
<head>
     <meta charset= "UTF-8" >
     <title>dojoConfig</title>
     <style type= "text/css" >
         .myNode {
             border: 1px solid # 999 ;
             margin:  0 .5em;
             padding:  0 .5em;
             background-color: #ccc;
             float: left;
         }
     </style>
     <script src= "dojo/dojo.js" ></script>
     <script>
         // Retrieve the dependencies
         require([ "dojo/query" "dojo/dom-construct" "dojo/domReady!" ],
                 function (query, domConstruct) {
                     function  log(msg){
                         var  c = document.getElementById( "console" );
                         if (!c){
                             c = domConstruct.create( "div" , {
                                 id:  "console"
                             }, document.body);
                         }
                         c.innerHTML +=  "<div>"  + msg +  "</div>" ;
                     }
                     var  myObject = {
                         foo:  "bar" ,
                         myHandler:  function (evt){
                             //still contrived!
                             //假设evt为事件对象:W3C标准中,使用evt.target,而IE为evt.srcElement
                             log( "The value of foo is "  this .foo +  ", from "  + (evt && evt.target ? evt.target.id : window.event.srcElement.id));
                         }
                     };
                     var  container = document.getElementById( "nodeContainer" );
                     for ( var  i= 0 ; i< 5 ; i++){
                         domConstruct.create( "div" , {
                             id:  "node-"  + (i+ 1 ),
                             className:  "myNode" ,
                             innerHTML:  "Fake button "  + (i+ 1 )
                         }, container);
                     }
                     query( ".myNode" ).forEach( function (node){
                         node.onclick = myObject.myHandler;
                     });
                 });
     </script>
</head>
<body>
<div id= "nodeContainer" >
</div>
</body>
</html>

输出结果:

The value of foo is undefined, from node-1

The value of foo is undefined, from node-2

The value of foo is undefined, from node-3

分析原因:

    期望的结果是显示显示"The value of 'foo' is bar",但我们得到信息:The value of 'foo' is undefined。

    (1)node.onclick = myObject.myHandler

    在这里 myObject.myHandler 经过解析,变成了函数 myHandler,仅仅是函数而已。而 myHandler 做为 myObject 的方法的这一事实被完全舍弃了。(将 myObject.myHandler 赋值给 onclick ,  context 什么事儿,它才不管这个函数在哪定义,他完全将这个函数同对象本身剥离了。)

    (2)如果你依然困惑,只需要记住在 JavaScript中 Functions objects同其他非原始类型一样,是引用传递,而非值传递。在我们上面的例子中,我们不过将 onclick  设置为一个直接指向 myObject.myHandler的引用。

    使用.apply和.call切换运行上下文execution contexts

1
2
3
4
5
query( ".myNode" ).forEach( function (node){
       node.onclick =  function (evt){
       myObject.myHandler.call(myObject,evt);
       };
});

    将触发绑定事件代码修改成如上内容,就可得到想要的结果。

(1)使用lang.hitch绑定运行上下文execution context

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<!DOCTYPE html>
<html>
<head>
     <meta charset= "UTF-8" >
     <title>dojoConfig</title>
     <style type= "text/css" >
         .myNode {
             border: 1px solid # 999 ;
             margin:  0 .5em;
             padding:  0 .5em;
             background-color: #ccc;
             float: left;
         }
     </style>
     <script src= "dojo/dojo.js" ></script>
     <script>
         // Retrieve the dependencies
         require([ "dojo/_base/lang" , "dojo/query" "dojo/dom-construct" "dojo/domReady!" ],
                 function (lang,query, domConstruct) {
                     function  log(msg){
                         var  c = document.getElementById( "console" );
                         if (!c){
                             c = domConstruct.create( "div" , {
                                 id:  "console"
                             }, document.body);
                         }
                         c.innerHTML +=  "<div>"  + msg +  "</div>" ;
                     }
                     var  myObject = {
                         foo:  "bar" ,
                         myHandler:  function (evt){
                             //still contrived!
                             log( "The value of foo is "  this .foo +  ", from "  + (evt && evt.target ? evt.target.id : window.event.srcElement.id));
                         }
                     };
                     var  container = document.getElementById( "nodeContainer" );
                     for ( var  i= 0 ; i< 5 ; i++){
                         domConstruct.create( "div" , {
                             id:  "node-"  + (i+ 1 ),
                             className:  "myNode" ,
                             innerHTML:  "Fake button "  + (i+ 1 )
                         }, container);
                     }
                     query( ".myNode" ).forEach( function (node){
                         node.onclick = lang.hitch(myObject, myObject.myHandler);
                     });
                 });
     </script>
</head>
<body>
<div id= "nodeContainer" >
</div>
</body>
</html>

说明:

lang.hitch可以指定函数的上下文,关键代码:

1
2
3
query( ".myNode" ).forEach( function (node){
      node.onclick = lang.hitch(myObject, myObject.myHandler);
});

(2)参数对象The arguments object

    arguments object 并非一个真正的JavaScript的Array object;尽管某些方面同数组类似(如采用数字下标索引,包含 length 属性等),但其是只读的,因此某些 Array 方法对其无效(如 Array.prototype.slice)。

(3)使用lang.partial修改函数签名function signatures

1
2
3
4
query( ".myNode" ).forEach( function (node){
      //don't forget: method first, fixed arguments second!
      node.onclick = lang.partial(myObject.myHandler, myObject);
});

 (4)将 hitch和partial 的优点整合在一起

    是不是很想把 htich 的优点(强制运行上下文)和partial的优点(预置参数)整合在一起?好吧,lang.hitch进一步增强可以完成以上两种工作:你可以在context和method 两个参数后,再添加任意数量的参数,lang.hitch 将会绑定上下文,预置参数,生成新的函数。


    备注:hitch 和 partial 是通往函数式编程的入口(参考: functional programming);Dojo Toolkit  在 dojox/lang/functional 下提供了很多函数式编程技术东西,建议你有空看看。







     本文转自stock0991 51CTO博客,原文链接:http://blog.51cto.com/qing0991/1563608,如需转载请自行联系原作者





相关文章
|
2月前
|
C# Python
Python Tricks : Function Argument Unpacking
Python Tricks : Function Argument Unpacking
27 1
|
3月前
|
缓存 JavaScript 前端开发
LeetCode 241. Different Ways to Add Parentheses
给定一个含有数字和运算符的字符串,为表达式添加括号,改变其运算优先级以求出不同的结果。你需要给出所有可能的组合的结果。有效的运算符号包含 +, - 以及 * 。
84 0
LeetCode 241. Different Ways to Add Parentheses
Stylus - 方法(Functions)
Stylus - 方法(Functions)
91 0
Stylus - 方法(Functions)
|
数据库
When Tech Meets Love – Smarter Ways to NOT be Single
It’s that time of year again. Single’s Day (a.k.a Double 11) is just around the corner, people buying gifts for loved ones.
1634 0
When Tech Meets Love – Smarter Ways to NOT be Single
|
存储 程序员 C#
艾伟_转载:C# Design Patterns (5) - Prototype
本帖介绍 Prototype Pattern (原型模式),并以一个「人事招聘程序」作为示例来说明。--------------------------------------------------------本帖的示例下载点:http://files.cnblogs.com/WizardWu/090713.zip第一个示例为 Console Mode (控制台应用程序) 项目,第二个示例为 ASP.NET 网站项目。
1450 0