重载是指函数或者方法有相同的名称,可是参数个数或类型不相同的情形,这样的同名不一样参的函数或者方法之间,互相称之为重载函数或方法。数组
咱们知道,JavaScript函数能够随意传递任意数量、任意类型的参数,那么它有没有重载呢?微信
答案是有的,下面咱们经过3种方法来实现JavaScript的函数重载。闭包
咱们有一个people对象app
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"]
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"]
这种方式你们确定都能看懂,就很少说啦。this
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)方法是核心。咱们着重分析一下为何这里会有闭包,能够保存上一个注册的函数。spa
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函数执行完后,仍然被另外的变量所引用,致使它的执行环境没法销毁,因此产生了闭包。code
所以,每次调用addMethod,都会有一个执行环境保存着当时的old和fn,因此在调用people.find()的时候能够找到当时注入的fn,实现函数重载。对象
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"]
这样写其实感受有点多此一举了,就当成是另一种思路吧。ip
JavaScript能够实现函数重载,主要有两种思想: