JavaScript实现函数重载

栏目: JavaScript · 发布时间: 6年前

内容简介:重载是指函数或者方法有相同的名称,但是参数个数或类型不相同的情形,这样的同名不同参的函数或者方法之间,互相称之为重载函数或方法。我们知道,JavaScript函数可以随意传递任意数量、任意类型的参数,那么它有没有重载呢?

JavaScript实现函数重载

重载是指函数或者方法有相同的名称,但是参数个数或类型不相同的情形,这样的同名不同参的函数或者方法之间,互相称之为重载函数或方法。

我们知道,JavaScript函数可以随意传递任意数量、任意类型的参数,那么它有没有重载呢?

答案是有的,下面我们通过3种方法来实现JavaScript的函数重载。

实现

0. 目标

我们有一个people对象

var people = {
  values: ['Dean Edwards', 'Sam Stephenson', 'Alex Russell', 'Dean Tom']
};

想要实现一个find方法,不传参数的时候,输出所有名字,只传1个参数的时候,输出所有fristName和参数相同的名字,传2个参数的时候,输出所有firstName和lastName和2个参数分别相同的名字。

people.find();                          // ["Dean Edwards", "Sam Stephenson", "Alex Russell", "Dean Tom"]
people.find('Dean');                    // ["Dean Edwards", "Dean Tom"]
people.find('Dean', 'Edwards');            // ["Dean Edwards"]

1. 利用arguments和switch实现重载

people.find = function () {
  switch (arguments.length) {
    case 0:
      return this.values;

    case 1:
      return this.values.filter((value) => {
        var firstName = arguments[0];
        return value.indexOf(firstName) !== -1 ? true : false;
      });

    case 2:
      return this.values.filter((value) => {
        var fullName = `${arguments[0]} ${arguments[1]}`;
        return value.indexOf(fullName) !== -1 ? true : false;
      });
  }
};

console.log(people.find());                 // ["Dean Edwards", "Sam Stephenson", "Alex Russell", "Dean Tom"]
console.log(people.find('Dean'));           // ["Dean Edwards", "Dean Tom"]
console.log(people.find('Dean', 'Edwards'));   // ["Dean Edwards"]

这种方式大家肯定都能看懂,就不多说啦。

2. 利用arguments和闭包实现重载

function addMethod (object, name, fn) {
  // 把前一次添加的方法存在一个临时变量old中
  var old = object[name];

  // 重写object[name]方法
  object[name] = function () {
    if (fn.length === arguments.length) {
      // 如果调用object[name]方法时,如果实参和形参个数一致,则直接调用
      return fn.apply(this, arguments);
    } else if (typeof old === 'function') {
      // 如果实参形参不一致,判断old是否是函数,如果是,就调用old
      return old.apply(this, arguments);
    }
  };
}

addMethod(people, 'find', function() {
  return this.values;
});

addMethod(people, 'find', function(firstName) {
  return this.values.filter((value) => {
    return value.indexOf(firstName) !== -1 ? true : false;
  });
});

addMethod(people, 'find', function(firstName, lastName) {
  return this.values.filter((value) => {
    var fullName = `${firstName} ${lastName}`;
    return value.indexOf(fullName) !== -1 ? true : false;
  });
});

console.log(people.find());                     // ["Dean Edwards", "Sam Stephenson", "Alex Russell", "Dean Tom"]
console.log(people.find('Dean'));               // ["Dean Edwards", "Dean Tom"]
console.log(people.find('Dean', 'Edwards'));    // ["Dean Edwards"]

这里addMethod(object, name, fn)方法是核心。我们着重分析一下为什么这里会有闭包,可以保存上一个注册的函数。

function addMethod (object, name, fn) {
  // object, name, fn是传入的3个参数
  var old = object[name];

  object[name] = function () {
    // 这里对old和fn进行了引用
    if (fn.length === arguments.length) {
      return fn.apply(this, arguments);
    } else if (typeof old === 'function') {
      return old.apply(this, arguments);
    }
  };
}

object是另外一个引用对象,它的一个方法中引用了old和fn,所以对于addMethod来说,它的局部变量在addMethod函数执行完后,仍然被另外的变量所引用,导致它的 执行环境无法销毁,所以产生了闭包

因此,每次调用addMethod,都会有一个执行环境保存着当时的old和fn,所以在调用people.find()的时候可以找到当时注入的fn,实现函数重载。

3. 利用Proxy和arguments实现重载

var proxy = new Proxy(people, {
  get: function (target, key, receiver) {
    if (key === 'find') {
      return function () {
        switch (arguments.length) {
          case 0:
            return this.values;
      
          case 1:
            return this.values.filter((value) => {
              var firstName = arguments[0];
              return value.indexOf(firstName) !== -1 ? true : false;
            });
      
          case 2:
            return this.values.filter((value) => {
              var fullName = `${arguments[0]} ${arguments[1]}`;
              return value.indexOf(fullName) !== -1 ? true : false;
            });
        }
      };
    }

    return Reflect.get(target , key , receiver);
  },

  set: function (target, key, value, receiver) {
    return Reflect.set(target, key, value, receiver);
  }
});

console.log(proxy.find());                     // ["Dean Edwards", "Sam Stephenson", "Alex Russell", "Dean Tom"]
console.log(proxy.find('Dean'));               // ["Dean Edwards", "Dean Tom"]
console.log(proxy.find('Dean', 'Edwards'));   // ["Dean Edwards"]

这样写其实感觉有点画蛇添足了,就当成是另外一种思路吧。

总结

JavaScript可以实现函数重载,主要有两种思想:

  1. 利用arguments类数组来判断接收参数的个数
  2. 利用闭包保存以前注册进来的同名函数

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Effective Java

Effective Java

Joshua Bloch / Addison-Wesley Professional / 2018-1-6 / USD 54.99

The Definitive Guide to Java Platform Best Practices—Updated for Java 9 Java has changed dramatically since the previous edition of Effective Java was published shortly after the release of Jav......一起来看看 《Effective Java》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

html转js在线工具
html转js在线工具

html转js在线工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具