Open classicemi opened 9 years ago
假设现在有这样一个场景,一个下单页面,需要根据特定的条件去计算购物车商品的总价,特定的条件包括但不限于选中的商品、是否选择折扣、是否叠加套餐和运费险等。这时我们通常需要写一个用来计算总价的函数getTotalPrice(),然而,函数的参数是不确定的,同时函数内的逻辑也会根据参数的不同而有所变化,最简单的方法是在函数内部对参数进行判断:
getTotalPrice()
如果参数分开传入,那么函数的伪代码可能写成这样:
function getTotalPrice(selectedGoods, isDiscounted, pacakge) { var totalPrice = 0; if (selectedGoods) { totalPrice = ...; if (isDiscounted) { // 计算折扣 if (package) {...} } else if (pacakge) {...} return totalPrice; } else { return 0; } }
有的人可能觉得将参数分开传入函数看起来比较乱,会习惯用一个参数对象包裹一下,在函数内部再对这个对象进行解析。看起来确实有一定的改进,但我认为并没有什么本质上的区别。
现在希望能够做到针对不同参数的情况,在函数内部只书写针对特定个数参数的逻辑,不去写乱七八糟的if-else语句或是参数对象的解析逻辑。同时,这些函数共用一个函数名,并且该逻辑可扩展,即可以随时根据需要,添加函数。
if-else
通过对需求的分析,应该会有这样的一个工具函数:
var methods = {}; addFunction(methods, 'getTotalPrice', function(selectedGoods) {...}); addFunction(methods, 'getTotalPrice', function(selectedGoods, isDiscounted) {...}); addFunction(methods, 'getTotalPrice', function(selectedGoods, isDiscounted, pacakge) {...});
这样,在添加每个函数的时候,只需要写针对特定参数的逻辑,调用getTotalPrice的时候,自动根据参数长度实际调用不同的函数。
getTotalPrice
很容易想到要对不同的函数进行缓存,同时为了公用同一个函数名,缓存的函数需要匿名,进而联想到闭包可以保存局部变量的引用的特性,以下是addFunction的实现:
addFunction
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则是典型的闭包的应用,并没有把函数存储在任何典型的数据结构中。
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方法的通用性。另外,每添加一个函数,就会增加一层嵌套,调用深度过深的话性能开销也会比较大,使用的时候要进行权衡。
这算是利用闭包实现类似方法重载的方案了,很精髓啊
假设现在有这样一个场景,一个下单页面,需要根据特定的条件去计算购物车商品的总价,特定的条件包括但不限于选中的商品、是否选择折扣、是否叠加套餐和运费险等。这时我们通常需要写一个用来计算总价的函数
getTotalPrice()
,然而,函数的参数是不确定的,同时函数内的逻辑也会根据参数的不同而有所变化,最简单的方法是在函数内部对参数进行判断:如果参数分开传入,那么函数的伪代码可能写成这样:
有的人可能觉得将参数分开传入函数看起来比较乱,会习惯用一个参数对象包裹一下,在函数内部再对这个对象进行解析。看起来确实有一定的改进,但我认为并没有什么本质上的区别。
现在希望能够做到针对不同参数的情况,在函数内部只书写针对特定个数参数的逻辑,不去写乱七八糟的
if-else
语句或是参数对象的解析逻辑。同时,这些函数共用一个函数名,并且该逻辑可扩展,即可以随时根据需要,添加函数。通过对需求的分析,应该会有这样的一个工具函数:
这样,在添加每个函数的时候,只需要写针对特定参数的逻辑,调用
getTotalPrice
的时候,自动根据参数长度实际调用不同的函数。很容易想到要对不同的函数进行缓存,同时为了公用同一个函数名,缓存的函数需要匿名,进而联想到闭包可以保存局部变量的引用的特性,以下是
addFunction
的实现:在
addFunction
方法的作用域中,保存了原方法的引用,通过对参数长度的比较确定最终执行哪个匿名函数,要注意的是一个函数的length
属性表示改函数接受的形参数量,而arguments.length
表示实际传入的参数数量。匿名函数访问oldFunc
和fn
则是典型的闭包的应用,并没有把函数存储在任何典型的数据结构中。要注意的是,这种方式只能针对不同数量的参数,不能判断参数的名称或类型,如果要判断的话,势必会牺牲
addFunction
方法的通用性。另外,每添加一个函数,就会增加一层嵌套,调用深度过深的话性能开销也会比较大,使用的时候要进行权衡。