如何重用具有不同变量的闭包

时间:2016-07-01 00:03:36

标签: javascript closures

我想重用函数sayMyName但使用不同的变量。如果我以错误的方式构建这个问题,请告诉我,以及我尝试做什么的最佳做法。



var sayMyName = function(myName) {
  console.log(myName)
};

var name1 = function() {
  // myName should not be a global variable 
  // because there may be more variables/functions 
  // that I'd want to closed inside sayMyName(). 
  // Declaring all of them to the global scope is not ideal.
  var myName = 'Walter';

  sayMyName();
  // I don't want to pass in myName as argument like this:
  // sayMyName(myName);
  // I want myName to be implicitly included in sayMyName()
  // I want to pass in everything that is declared in name1 to sayMyName() implicitly.
};

var name2 = function() {
  var myName = 'White'; 
  sayMyName();
}

name1(); // should give me 'Walter'
name2(); // should give me 'White'




3 个答案:

答案 0 :(得分:2)

我不确定你为什么特别想要一个闭包,但通过查看你的例子,似乎绑定比闭包更合适。



var sayMyName = function(myName) {
  console.log(myName)
};

var name1 = sayMyName.bind(undefined, 'Walter');
var name2 = sayMyName.bind(undefined, 'White');

name1(); // log 'Walter'
name2(); // log 'White'




答案 1 :(得分:1)

将变量myName移动到最外层范围:



var myName;

var sayMyName = function() {
  console.log(myName)
};

var name1 = function() {
  myName = 'Walter';
  sayMyName();
};

var name2 = function() {
  myName = 'White'; 
  sayMyName();
}

name1(); // should give me 'Walter'
name2(); // should give me 'White'




更新:考虑一下,如果您愿意使用非标准的Error.stack属性,愿意使用命名函数,并愿意使用命名约定,那么您可以实现你的目标:



function sayMyName() {
  try {
    throw new Error();
  }
  catch (e) {
    if (e.stack) { // non-standard attribute
      var reNames = /^\s*at myNameIs([A-Z][^(\s]*)\s*\(/mg;
      reNames.lastIndex = 0;

      var buffer = [];
      for (var match = reNames.exec(e.stack); null !== match; match = reNames.exec(e.stack)) {
        buffer.push(match[1]);
      }

      console.log(buffer.join(" "));
    }
  }
}

function myNameIsWalter() {
  sayMyName();
}

function myNameIsWhite() {
  myNameIsWalter();
};

myNameIsWalter();  // "Walter"
myNameIsWhite();   // "Walter White"




...如果你愿意使用eval(糟糕!!!),那么你可以做下面的更好的事情:



var sayMyName = function () {
  try {
    throw new Error();
  }
  catch (e) {
    if (e.stack) { // non-standard attribute
      var reNames = /^\s*at ([_a-zA-Z][_a-zA-Z0-9]+(\.[_a-zA-Z][_a-zA-Z0-9]+)*)/mg;
      reNames.lastIndex = 0;

      var reMyName = /\bmyName\s*=\s*(?:"([^"]*)"|'([^']*)')/g;

      var identifier, definition, match, myName, buffer = [];
      while (null !== (match = reNames.exec(e.stack))) {
        try {
          identifier = match[1];
          if ("sayMyName" !== identifier) {
            definition = eval(match[1] + '.toString()');
            if (/\bsayMyName\(\)/.test(definition)) {
              reMyName.lastIndex = 0;
              buffer.length = 0;
              while (null !== (myName = reMyName.exec(definition))) {
                buffer.push(myName[1]);
              }
              console.log(buffer.join(" "));
            }
          }
        }
        catch (_) {
          // continue
        }
      }
    }
  }
};

function name1() {
  var myName = "Walter";
  sayMyName();
}

function name2() {
  var myName;
  myName = "Walter";
  myName = "White";
  sayMyName();
}

name1(); // "Walter"
name2(); // "Walter White"




您甚至可以使用非标准的Function.caller属性,这可能是最干净的方法(如果它在您的浏览器中有效 - 由于某种原因它是非标准的):



function sayMyName() {
  var reMyName = /\bmyName\s*=\s*(?:"([^"]*)"|'([^']*)')/g;

  var definition, buffer = [];
  for (var caller = sayMyName.caller; caller; caller = caller.caller) {
    definition = caller.toString();
    if (/\bsayMyName\(\)/.test(definition)) {
      reMyName.lastIndex = 0;
      buffer.length = 0;
      while (null !== (myName = reMyName.exec(definition))) {
        buffer.push(myName[1]);
      }
      console.log(buffer.join(" "));
    }
  }
};

function name1() {
  var myName = "Walter";
  sayMyName();
}

function name2() {
  var myName;
  myName = "Walter";
  myName = "White";
  sayMyName();
}

name1(); // "Walter"
name2(); // "Walter White"




但这可以说不仅仅是传递参数的代码。

答案 2 :(得分:0)

如果你想要关闭,那就是这个例子。

function sayMyName(myName){
   return function(){
      console.log(myName); //myName is available from parent scope
      return myName; 
   }
}
var name1 = sayMyName('Walter');
var name2 = sayMyName('White');
//no console output by now
name1(); //Walter
name2(); //White
//myName is not available in global scope
console.log(myName); //undefined