从已定义的函数创建闭包

Create a closure from already defined function?

本文关键字:创建 闭包 函数 定义      更新时间:2023-09-26

我想扩展Array.sort()以接受另一个参数。这个问题有一个使用闭包的解决方案,所以这个代码有效:

var create_comparator = function(c) {
  return function(a,b) { console.log(c); return a-b };
};
arr.sort( create_comparator('test') );

然而,在我的情况下,我已经定义了这样的函数:

var myComp1 = function(a,b) { console.log(c); return a-b };

返回预定义的函数不起作用:

var create_comparator = function(sortfn, c) {
  // Uncaught ReferenceError: c is not defined 
  return sortfn;      
};
var arr = [7, 4, 9, 2, 1];
arr.sort( create_comparator(myComp1, 'test') );

我想这是因为c在创建原始函数时没有定义。我尝试用return function(a,b) { sortfn(a,b); }创建一个新的闭包,但也不起作用。

使用这种设置,是否可以为预定义的功能提供额外的参数?这个问题还有别的解决办法吗?

您的示例并没有真正说明您对其他参数所做的操作。我仍然会尝试并建议使用分部。。。类似:

var myComp1 = function (c, a, b) { console.log(c); return a-b };
arr.sort(myComp1.bind(null, "test"));

或者,如果您仍然想将其抽象为生成器函数:

var myComp1 = function (c, a, b) { console.log(c); return a-b };
var create_comparator = function(sortfn, c) {
  return sortfn.bind(null, c);      
};

编辑:另一种方式!这可能是你努力实现的最好结果。这很酷的一点是,您可以将任意数量的参数附加到排序函数中,这使得额外的参数是可选的,因此您也可以将它们用作普通排序比较器。

var myComp1 = function (a, b, c) { if (c) { console.log(c); } return a-b };
var create_comparator = function() {
    var sortfn = arguments[0], 
    partial = Array.prototype.slice.call(arguments, 1);
    return function() {
      var args = Array.prototype.slice.call(arguments).concat(partial);
      return sortfn.apply(null, args);
    }
};

您当然不能追溯修改myComp1以关闭来自不同范围的局部变量c;这根本不是闭包的工作方式,也不是局部变量的工作方式。首先,您应该简单地正确定义myComp1

但如果你不能做到这一点,那么就有一种解决方案。

因为myComp1引用的c而不是范围内的局部变量,所以它真正引用的是global变量c;也就是说,它引用全局对象上名为'c'的属性(如果主机是Web浏览器,则为window)。因此,您可以创建一个包装器函数,将局部变量复制到全局对象上,然后调用myComp1;像这样的东西:

var wrapped_myComp1 = function (a,b,c) {
    window.c = c;
    var ret = myComp1(a,b);
    delete window.c;
    return ret;
};

它非常难看,这意味着这个函数是不可重入的(因为每次调用都会覆盖其他调用的c),但它应该可以工作。

函数myComp1的问题是函数试图使用未定义的全局变量c。在JavaScript中,函数具有词法作用域,这意味着函数使用定义它们的作用域。只有关闭不足以解决你的问题。尝试在闭包中分配c变量,比如id这个代码:

 var arr = [1,4,3,5,7,1,2],
        c;//it's a global variable, this is not a good approach. Good approach is change myComp1 definition, if you can.
    var myComp1 = function(a,b) { console.log(c); return a-b };
    var comp = function(prop) {
        c = prop; //this assignment push prop variable to global variable c, that uses in your function
        return myComp1;
    }
console.log(arr.sort(comp('additional_param')));

这将适用于

var c = 'test'
var myComp1 = function(a,b) { console.log(c); return a-b };
arr.sort( myComp1 );

这里闭包定义了c(但你需要如上所述定义它,如果你没有定义c,那么你会得到你得到的错误)。