PhoneGap中文网

 找回密码
 立即注册
查看: 16086|回复: 0
打印 上一主题 下一主题

JavaScript函数重载

[复制链接]

87

主题

87

帖子

327

积分

中级会员

Rank: 3Rank: 3

积分
327
跳转到指定楼层
楼主
发表于 2017-7-25 15:52:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

本文和大家分享的主要是javascript中函数重载相关内容,一起来看看吧,希望对大家学习javascript 有所帮助。
  在一个业余项目中,我写了一个简单的 addMethod 函数,用于实现函数重载(Method Overloading) 。而所谓 函数重载 ,就是函数名称一样,但是输入输出不一样。或者说,允许某个函数有各种不同输入,根据不同的输入,调用不同的函数,然后返回不同的结果。
  addMethod函数如下:
  // addMethod - By John Resig (MIT Licensed)function addMethod(object, name, fn){
  var old = object[ name ];
  object[ name ] = function(){
  if ( fn.length == arguments.length )
  return fn.apply( this, arguments );
  else if ( typeof old == 'function' )
  return old.apply( this, arguments );
  };
  }
  所谓 addMethod 函数,简单的理解,就是给某个 object ,添加一个指定 name 的函数 fn 。它利用了 闭包 ,可以通过 old 变量将先后绑定的函数链接起来。
  你可以这样使用 addMethod 函数,将 find 函数直接添加到每个对象实例:
  function Users(){
  addMethod(this, "find", function(){
  // Find all users...
  });
  addMethod(this, "find", function(name){
  // Find a user by name
  });
  addMethod(this, "find", function(first, last){
  // Find a user by first and last name
  });
  }
  你也可以将 find 函数添加到对象的 prototype ,这样所有对象实例将共享 find 函数:
  function Users(){
  addMethod(Users.prototype, "find", function(){
  // Find all users...
  });
  addMethod(Users.prototype, "find", function(name){
  // Find a user by name
  });
  addMethod(Users.prototype, "find", function(first, last){
  // Find a user by first and last name
  });
  }
  users对象的 find 方法成功实现了重载,可以根据不同的输入调用不同的函数:
  var users = new Users();
  users.find(); // Finds all
  users.find("John"); // Finds users by name
  users.find("John", "Resig"); // Finds users by first and last name
  users.find("John", "E", "Resig"); // Does nothing
  这种方法有一些明显的缺陷:
  · 重载只能处理输入参数个数不同的情况,它不能区分参数的类型、名称等其他要素。(ECMAScript 4计划支持这一特性,称作Multimethods,然而该版本已被放弃)。
  · 重载过的函数将会有一些额外的负载,对于性能要求比较高的应用,使用这个方法要慎重考虑。
  addMethod函数的秘诀之一在于 fn.length 。或许很多人并不清楚,所有函数都有一个 length 属性,它的值等于定义函数时的参数个数。比如,当你定义的函数只有1个参数时,其 length 属性为1:
  (function(foo){}).length == 1
  我做了一下测试,发现这个实现 函数重载 的方法适用于所有浏览器,如果有问题的话请与我联系。
  如果你担心只绑定单个函数时的性能问题,你可以使用如下 addMethod 函数:
  // addMethod - By John Resig (MIT Licensed)function addMethod(object, name, fn){
  var old = object[ name ];
  if ( old )
  object[ name ] = function(){
  if ( fn.length == arguments.length )
  return fn.apply( this, arguments );
  else if ( typeof old == 'function' )
  return old.apply( this, arguments );
  };
  else
  object[ name ] = fn;
  }
  这样绑定第一个函数时,将不会有额外的操作,既简单又快速。当绑定更多函数时,则与原 addMethod 函数一样,会有额外的性能损失。
  这样做还有一个额外的好处:对于那些参数个数不符合要求的函数调用,将统一又第一个绑定的函数处理。这时调用 find 方法的输出如下:
  var users = new Users();
  users.find(); // Finds all
  users.find("John"); // Finds users by name
  users.find("John", "Resig"); // Finds users by first and last name
  users.find("John", "E", "Resig"); // Finds all
  本文介绍的方法不能改变世界,但是它很代码量很少、很简单,巧妙地使用了JavaScript的特性。因此,我在我的书《Secrets of the JavaScript Ninja》也介绍了这个方法。
  完整示例
  根据原文介绍的方法,译者实现了一个完整的示例代码:
  function addMethod(object, name, fn){
  var old = object[name];
  object[name] = function()
  {
  if (fn.length == arguments.length)
  return fn.apply(this, arguments);
  else if (typeof old == 'function')
  return old.apply(this, arguments);
  };
  }
  // 不传参数时,返回所有namefunction find0(){
  return this.names;
  }
  // 传一个参数时,返回firstName匹配的namefunction find1(firstName){
  var result = [];
  for (var i = 0; i < this.names.length; i++)
  {
  if (this.names.indexOf(firstName) === 0)
  {
  result.push(this.names);
  }
  }
  return result;
  }
  // 传两个参数时,返回firstName和lastName都匹配的namefunction find2(firstName, lastName){
  var result = [];
  for (var i = 0; i < this.names.length; i++)
  {
  if (this.names === (firstName + " " + lastName))
  {
  result.push(this.names);
  }
  }
  return result;
  }
  function Users(){
  addMethod(Users.prototype, "find", find0);
  addMethod(Users.prototype, "find", find1);
  addMethod(Users.prototype, "find", find2);
  }
  var users = new Users();
  users.names = ["John Resig", "John Russell", "Dean Tom"];
console.log(users.find()); // 输出[ 'John Resig', 'John Russell', 'Dean Tom' ]
console.log(users.find("John")); // 输出[ 'John Resig', 'John Russell' ]
console.log(users.find("John", "Resig")); // 输出[ 'John Resig' ]
console.log(users.find("John", "E", "Resig")); // 输出undefined
  凭直觉, 函数重载 可以通过 if…else 或者 switch 实现,这就不去管它了。jQuery之父John Resig提出了一个非常巧(bian)妙(tai)的方法,利用了闭包。
  从效果上来说, users 对象的 find 方法允许3种不同的输入: 0个参数时,返回所有人名;1个参数时,根据firstName查找人名并返回;2个参数时,根据完整的名称查找人名并返回。
  难点在于, users.find 事实上只能绑定一个函数,那它为何可以处理3种不同的输入呢?它不可能同时绑定3个函数 find0 , find1 与 find2 啊!这里的关键在于 old 属性。
  由 addMethod 函数的调用顺序可知, users.find 最终绑定的是 find2 函数。然而,在绑定 find2 时, old 为 find1 ;同理,绑定 find1 时, old 为 find0 。3个函数 find0 , find1 与 find2 就这样通过闭包链接起来了。
  根据 addMethod 的逻辑,当 fn.length 与 arguments.length 不匹配时,就会去调用 old ,直到匹配为止。


来源:Fundebug博客
it营
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐 上一条 /1 下一条

ionic4视频教程

Archiver|手机版|小黑屋| PhoneGap中文网 ( 京ICP备13027796号-1 )  

GMT+8, 2024-11-27 06:20 , Processed in 0.059521 second(s), 29 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表