`
seaizon
  • 浏览: 138548 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Javascript Function()扩展(转)

 
阅读更多

Javascript Function()扩展

1、概述
                                                        
在 Javascript中,function非常灵活且功能强大。我们可以通过new Function(‘’,’’) 、eval()来等动态构建函数,这在别的语言(Java)中很难做到的。但这里不是介绍Function的特性,而是考量Function函数的扩展, 比较Mootools1.2,Prototype1.6,Ext2.02中对Function函数的扩展,分析在构建新的类库时,怎样扩展 Function函数。

Function.prototype有两个特有用,使用频率极高的两个函数,一是 function.apply(thisArg[, argsArray]);,二是fun.call(thisArg[, arg1[, arg2[, ...]]]);。两个函数的作用都是一样的,更改函数作用域并执行函数。使函数的this指向thisArg。也可以它变换成调用执行 thisArg.fun.(argsArray或arg1[, arg2[, ...]])。Call与Apply不同的地方就是一个采用数组传入参数,一个采用Arguments的形式。

除了这种更改函数作用域 并执行函数的功能,我们在操作函数时,还需要别的什么功能呢?试想一下Java,C++,C#等语言的中函数。我们会想到函数回调,函数委托,函数包装。 这对应着模式设计中的观察者模式,代理模式,装饰模式。这样在JavaScript的函数中又如何处理呢?

说到回调函数,在 JavaScript中,我们也并不陌生,我们在网页上经常会写如:node.onclick=myFn,为该Node的click事件注册一个处理函 数。这个处理函数就是回调函数。它要按一定的格式来写。比如它默认把onclick的事件做为参数传入到myFn中。也就是说myFn函数要这样 写:function(e){…};在函数中就可以调用系统传进来e,根据e做相关的处理(IE中不兼容)。但是在Javascript中,对于函数的参 数没有其它的语言那样的要求(个数,类型等)。不管你的函数有几个参数,它只传入一个参数。当然啊,对于Javascript的其它的回调就不一定是一个 参数了。

这样看来,为某个函数创建回调函数的意义不大,但是在代码采用createCallBack的方式比直接写函数名有更好的可理 解和可读性。假如我的一个函数如下:funciton(e,x1,x2,x3){},采用createCallBack的方式,我们可以预先设定 x1,x2,x3的值。这样一来,我们就可以做到为多种回调写一个处理函数。只在在注册创建回调时设定值来区分。

函数委托,就是本来是 我这个函数的工作,我要委托别的函数来实现。但是调用的却是我这个函数。在JavaScript中,改变了函数的执行作用域,其实就改变函数的归属。本来 属于A对象,现在可以就变成了B对象。函数委托或代理其实就只要改变这个执行作用域就可以了。与Apply不同的,改变执行作用域的时候不执行该函数,来 推迟到下一次的调用时才执行。那不就是把这个函数代理包装另外一个函数,实际上还是执行这个改变了作用域的函数。

函数包装,就把原来的 函数包装成功能更强大的函数。在JavaScript中,要包装这个函数,那首先得把这个函数传到包装的函数中来,然后才进行相关的加强装饰操作。因为函 数是有执行作用域的,对于被包装的函数,我们的要求肯定是和包装后的函数的执行作用域是一样的。这样一来,才相当于调用那个被包装的函数,同时又加强了功 能。

上面三种都是对函数对于一些改变成为另外一个函数,那么函数是不是还需要有一些操作呢,比如我想在调用这个函数时1s后执行呢,比 如我们每隔执行这个函数呢?还有在执行这个函数之前,想执行别的函数,或之后执行别的函数?定时或间隔执行在操作网页的样式渐变有很大的作用。
采 用函数名表式:createCallBack, createDelegate, createWrap, delay, periodical, before,after,在扩展Function时,我们大约就只需要这几种操作。那么这几种操作在 Mootools1.2,Prototype1.6,Ext2.02中是否全都实现了呢,又是如何实现的呢?

 
2.分析与比较


在Mootools1.2,Prototype1.6,Ext2.02都实现了callback,degelate。不过感觉起来差强人意。先
2.1说callback吧:
Ext中:

Java代码  收藏代码
  1. createCallback : function(){   
  2. var args = arguments;   
  3. var method = this ;   
  4. return  function() {   
  5. return  method.apply(window, args);   
  6. };   
  7. }   

 
这个callback,没有处理闭包函数传进来的参数,比如在事件回调中,会传入event进来,而这样却处理不了。唯一能处理的是闭包函数无传进来的参数的回调。而函数的执行作用域竟然是window,理应该是调用该闭包函数的this。
ProtoType中:

Java代码  收藏代码
  1. bindAsEventListener: function() {   
  2. var __method = this , args = $A(arguments), object = args.shift();   
  3. return  function(event) {   
  4. return  __method.apply(object, [event || window.event].concat(args));   
  5. }   
  6. }   

 
这个也是完成callback的功能,不过我它只能完成事件的callback功能,如果要用的callback,就捉襟见肘了。在这 里,函数中的执行作用域也只是事先传来的object,觉得object不好,为什么不给一个默认的作用域为闭包函数的调用对象呢?可以改成 object||this。[event || window.event]改成$A(arguments)可以了。
Moo中:

Java代码  收藏代码
  1. bindWithEvent: function(bind, args){   
  2. return   this .create({bind: bind, event:  true , arguments: args});   
  3. },   
  4. create: function(options){   
  5. var self = this ;   
  6. options = options || {};   
  7. return  function(event){   
  8. var args = options.arguments;   
  9. args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1  :  0 );   
  10. if  (options.event) args = [event || window.event].extend(args);   
  11. var returns = function(){   
  12. return  self.apply(options.bind ||  null , args);   
  13. };   
  14. if  (options.delay)  return  setTimeout(returns, options.delay);   
  15. if  (options.periodical)  return  setInterval(returns, options.periodical);   
  16. if  (options.attempt)  return  $ try (returns);   
  17. return  returns();   
  18. };   
  19. },   

 发现ProtoType中一模一样的处理。只不过是集中在create()中了。
从上面三者可以看出来,它们都没有真正地实现callback函数。如下实现:

Java代码  收藏代码
  1. createCallBack : function(obj, args, appendArgs){   
  2. var method = this ;   
  3. return  function() {   
  4. var callArgs = args || arguments;   
  5. if (appendArgs ===  true ){   
  6. callArgs = Array.prototype.slice.call(arguments, 0 );   
  7. callArgs = callArgs.concat(args);   
  8. }else   if (typeof appendArgs ==  "number" ){   
  9. callArgs = Array.prototype.slice.call(arguments, 0 ); var applyArgs = [appendArgs,  0 ].concat(args); Array.prototype.splice.apply(callArgs, applyArgs); }   
  10. return  method.apply(obj || this || window, callArgs);   
  11. }; },   

 

这样一来,我们在创建Callback时,可以动态指定参数的位置,预设参数。突破了callback仅仅只是事件中的。

2.2 Delegate


Ext中:

 

Java代码  收藏代码
  1. createDelegate : function(obj, args, appendArgs){   
  2. var method = this ;   
  3. return  function() {   
  4. var callArgs = args || arguments;   
  5. if (appendArgs ===  true ){   
  6. callArgs = Array.prototype.slice.call(arguments, 0 );   
  7. callArgs = callArgs.concat(args);   
  8. }else   if (typeof appendArgs ==  "number" ){   
  9. callArgs = Array.prototype.slice.call(arguments, 0 ); var applyArgs = [appendArgs,  0 ].concat(args); Array.prototype.splice.apply(callArgs, applyArgs); }   
  10. return  method.apply(obj || window, callArgs);   
  11. };   
  12. },   

 感觉到一点不好的地方就是函数的作用域obj || window改成obj ||this|| window使用默认的时候指调用对象的本身。这样没有什么不好。

Prototype中:

Java代码  收藏代码
  1. bind: function() {   
  2. if  (arguments.length <  2  && arguments[ 0 ] === undefined)  return   this ;   
  3. var __method = this , args = $A(arguments), object = args.shift();   
  4. return  function() {   
  5. return  __method.apply(object, args.concat($A(arguments)));   
  6. }   
  7. }   

 

 

比Ext中的差远了。不能设定参数的位置。而且用bind命名,给人误解。myFn.bind(this,xx,yy),给人感觉和myFn.call(this,xx,yy)是一样的,修改执行作用域并执行。那里可以看得出来返回是函数。

Moo中:

 

Java代码  收藏代码
  1. bind: function(bind, args){   
  2. return   this .create({bind: bind, arguments: args});   
  3. },   

 
其调用create(),和Prototype中bind()差不多。

2.3包装

只有prototype中有:

Java代码  收藏代码
  1. wrap: function(wrapper) {   
  2. var __method = this ;   
  3. return  function() {   
  4. return  wrapper.apply( this , [__method.bind( this )].concat($A(arguments)));   
  5. }   
  6. },   

 

一不能指定作用域,二不能用函数预设参数。

修改如下:

 

Java代码  收藏代码
  1. createWrap:function(wrapper,scope,args, appendArgs){   
  2. var _method = this ;   
  3. return  function() {   
  4. var allArgs = Array.prototype.slice.call(arguments, 0 );   
  5. return  wrapper.apply(scope|| this ,   
  6. [method.createDelegate(scope||this , args, appendArgs)].concat(allArgs));   
  7. }   
  8. },   

 
现在可以传入作用域,还可以指该被包装的函数的预设参数。同时能改变参数的位置。

Java代码  收藏代码
  1. var a = {   
  2. b: {   
  3. c: function () {   
  4. }   
  5. },   
  6.   
  7. f: function () {   
  8. alert(this ==a.b);   
  9. }   
  10. };   
  11.   
  12. a.b.c = a.f.wrap(function (F) {   
  13. F();   
  14. });   

 a.b.c();
最好是采用a.f.wrap(function (F) { F();})这样的形式来书写wrapper;

Delay吧;

Ext中:
defer : function(millis, obj, args, appendArgs){
var fn = this.createDelegate(obj, args, appendArgs);
if(millis){
return setTimeout(fn, millis);
}
fn();
return 0;
},

Protype中:
delay: function() {
var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
return window.setTimeout(function() {
return __method.apply(__method, args);
}, timeout);
},

Moo

delay: function(delay, bind, args){
return this.create({delay: delay, bind: bind, arguments: args})();
},


periodical: function(interval, bind, args){
return this.create({periodical: interval, bind: bind, arguments: args})();
},

periodical : function(millis, obj, args, appendArgs){
var fn = this.createDelegate(obj, args, appendArgs);
if(millis){
return setInterval(fn, millis);
}
fn();
return 0;
},

 

                                                                                prk      2008-7-30

 

转载自:http://jljlpch.iteye.com/blog/221646

分享到:
评论

相关推荐

    Javascript Function对象扩展之延时执行函数

    如果你在一个应用里面常常要“延时执行某某函数”,那末基于DRY的原则,可以针对Function全局对象进行扩展,为函数增加一个延时方法如delay,这样会让你的代码更简洁有效。 扩站Function对象增加delay方法如下: 代码...

    JavaScript中函数(Function)的apply与call理解

    主要介绍了JavaScript中函数(Function)的apply与call理解,本文讲解了JavaScript函数调用分为4中模式以及通过apply和call实现扩展和继承两方面,需要的朋友可以参考下

    javascript数组的扩展实现代码集合

    Array.prototype.del = function(n) { if (n = function() u00a0 var nr=[], me&gt;0) { nr[nr.length] = me[t = Math.floor(Math.random() * me.length)];

    源文件程序天下JAVASCRIPT实例自学手册

    源文件程序天下JAVASCRIPT实例自学手册 第1章 JavaScript语言概述 1.1 JavaScript是什么 1.1.1 JavaScript简史 1.1.2 JavaScript有何特点 1.2 JavaScript能做什么 1.2.1 表单数据合法性验证 1.2.2 页面特效 1.2.3 ...

    JavaScript中扩展Array contains方法实例

    javascript的Array没有contains方法,有时候这会不方便,contains方法实现很简单: 代码如下: function contains(a, obj) {  var i = a.length;  while (i–) {  if (a[i] === obj) {  return true;  }  }  ...

    JavaScript详解(第2版)

     8.5 通过原型扩展对象   8.5.1 使用prototype属性为对象添加属性   8.5.2 原型查找链   8.5.3 使用原型为对象添加方法   8.5.4 所有对象都有的属性和方法   8.5.5 创建子类及继承   8.6 应知应...

    javascript函数的解释

    62.addBehavior()是一种JS调用的外部函数文件其扩展名为.htc 63.window.focus()使当前的窗口在所有窗口之前. 64.blur()指失去焦点.与FOCUS()相反. 65.select()指元素为选中状态. 66.防止用户对文本框中输入文本:...

    ios-一个扩展简单搞定Native 调用 webView JavaScript.zip

    [self syncRunJsFunction:@"js_function_name" parameter:params complete:^(JSValue * value) { }];

    JavaScript中文参考手册

    本书是 JavaScript 语言的参考手册,包括核心语言中的对象和客户端、服务器端的扩展。JavaScript 是 Netscape 跨平台的基于对象的适合于客户和服务器的脚本语言。 本书已经更新于 JavaScript 1.2 的新特性,其它...

    【JavaScript源代码】如何在 Vue 中使用 JSX.docx

     JSX 是一种 Javascript 的语法扩展,JSX = Javascript + XML,即在 Javascript 里面写 XML,因为 JSX 的这个特性,所以他即具备了 Javascript 的灵活性,同时又兼具 html 的语义化和直观性 为什么要在 Vue 中使用...

    JavaScript基于扩展String实现替换字符串中index处字符的方法

    本文实例讲述了JavaScript基于扩展String实现替换字符串中index处字符的方法。分享给大家供大家参考,具体如下: 核心代码: String.prototype.replaceCharAt = function(n,c){ return this.substr(0, n)+ c + ...

    Surfingkeys:映射用于网络冲浪的键,使用javascript和键盘扩展浏览器

    Surfingkeys-使用JavaScript和键盘扩展浏览器。 Surfingkeys是另一个Chrome / Firefox扩展程序,本着VIM编辑器的精神提供基于键盘的导航和网络控制。 但这不仅适用于VIM用户,还适用于只需要一些更多捷径来实现其...

    JavaScript基础和实例代码

    JavaScript电子书,包括了JavaScript的大部分知识,可以帮助读者快速入门。内容如下: 第1章 JavaScript语言概述 1.1 JavaScript是什么 1.1.1 JavaScript简史 1.1.2 JavaScript有何特点 1.2 JavaScript能做什么 ...

    【JavaScript源代码】JavaScript中条件语句的优化技巧总结.docx

    JavaScript中条件语句的优化技巧总结  对多个条件使用 Array.includes function test(fruit) { if (fruit == 'apple' || fruit == 'strawberry') { console.log('red'); } } 上面的例子看起来不错。然而,...

    javascript Prototype 对象扩展

    Javascript当然也不例外,可是关于对象的引用问题,你考虑过么?通常的做法是一系列对象共享类的方法,而不是为每个对象复制一份函数。下面看看为每个对象复制一份函数的做法。 代码如下:var myobject=function...

    【JavaScript源代码】基于p5.js 2D图像接口的扩展(交互实现).docx

    基于p5.js 2D图像接口的扩展(交互实现)  本文为大家分享了基于p5.js 2D图像接口的扩展,供大家参考,具体内容如下 一、心跳笔刷 组织结构: 1.纵坐标取一定范围内的随机值,横坐标按规律递增。... function

    JavaScript Array对象扩展indexOf()方法

    背景:JavaScript中Array对象的标准方法中,没有indexOf()方法,可通过下面的代码扩展。 代码如下: if (!Array.prototype.indexOf) { Array.prototype.indexOf = function(elt) { var len = this.length &gt;&gt;&gt; 0; var ...

    JavaScript Array扩展实现代码

    如果其他浏览器没有实现此方法,可以用以下代码实现兼容: 代码如下: Array.prototype.indexOf = function(el, start) { var start = start || 0; for ( var i=0; i &lt; this.length; ++i ) { if ( this[i] === el...

    fly 有JavaScript写的

    -- 以下是JavaScript语句 --&gt; &lt;script type="text/javascript"&gt; //////////////////////////////////////////////////////////////////////////////////////////////////// // 扩展String对象,从style.left和style....

Global site tag (gtag.js) - Google Analytics