本文同步自个人 GitHubjavascript
假设如今有这样一个场景,一个下单页面,须要根据特定的条件去计算购物车商品的总价,特定的条件包括但不限于选中的商品、是否选择折扣、是否叠加套餐和运费险等。这时咱们一般须要写一个用来计算总价的函数getTotalPrice()
,然而,函数的参数是不肯定的,同时函数内的逻辑也会根据参数的不一样而有所变化,最简单的方法是在函数内部对参数进行判断:java
若是参数分开传入,那么函数的伪代码可能写成这样:git
function getTotalPrice(selectedGoods, isDiscounted, pacakge) { var totalPrice = 0; if (selectedGoods) { totalPrice = ...; if (isDiscounted) { // 计算折扣 if (package) {...} } else if (pacakge) {...} return totalPrice; } else { return 0; } }
有的人可能以为将参数分开传入函数看起来比较乱,会习惯用一个参数对象包裹一下,在函数内部再对这个对象进行解析。看起来确实有必定的改进,但我认为并无什么本质上的区别。github
如今但愿可以作到针对不一样参数的状况,在函数内部只书写针对特定个数参数的逻辑,不去写乱七八糟的if-else
语句或是参数对象的解析逻辑。同时,这些函数共用一个函数名,而且该逻辑可扩展,便可以随时根据须要,添加函数。缓存
经过对需求的分析,应该会有这样的一个工具函数:数据结构
var methods = {}; addFunction(methods, 'getTotalPrice', function(selectedGoods) {...}); addFunction(methods, 'getTotalPrice', function(selectedGoods, isDiscounted) {...}); addFunction(methods, 'getTotalPrice', function(selectedGoods, isDiscounted, pacakge) {...});
这样,在添加每一个函数的时候,只须要写针对特定参数的逻辑,调用getTotalPrice
的时候,自动根据参数长度实际调用不一样的函数。闭包
很容易想到要对不一样的函数进行缓存,同时为了公用同一个函数名,缓存的函数须要匿名,进而联想到闭包能够保存局部变量的引用的特性,如下是addFunction
的实现:app
function addFunction(object, funcName, fn) { var oldFunc = object[funcName]; object[funcName] = function() { return (fn.length === arguments.length ? fn : oldFunc).apply(this, arguments); } }
在addFunction
方法的做用域中,保存了原方法的引用,经过对参数长度的比较肯定最终执行哪一个匿名函数,要注意的是一个函数的length
属性表示改函数接受的形参数量,而arguments.length
表示实际传入的参数数量。匿名函数访问oldFunc
和fn
则是典型的闭包的应用,并无把函数存储在任何典型的数据结构中。函数
addFunction(methods, 'getTotalPrice', function(total) { console.log(total); }); addFunction(methods, 'getTotalPrice', function(total, discount) { console.log(total * discount); }); methods.getTotalPrice(20); // 输出20 methods.getTotalPrice(20, 0.8); // 输出16
要注意的是,这种方式只能针对不一样数量的参数,不能判断参数的名称或类型,若是要判断的话,势必会牺牲addFunction
方法的通用性。另外,每添加一个函数,就会增长一层嵌套,调用深度过深的话性能开销也会比较大,使用的时候要进行权衡。工具