【问题标题】:Get variable in scope without closure / wrapping function在没有闭包/包装功能的情况下获取范围内的变量
【发布时间】:2018-06-15 16:10:55
【问题描述】:

如果我有一个随时间变化的变量,并且我想保留它的特定实例,我必须将它包装在一个闭包中,如下所示:

function test(){
	var x = Math.random();
	// Is there an alternative to using the following closure:
	var printnum = (function(num){ 
		return function(){
			console.log(num);
		}
	})(this.x); // Because I think this is ugly
	
	return printnum;
}

var a = test();
var b = test();

a(); //number
a(); //same as above
b(); //different number
b(); //same as above

在 PHP 中,您可以像这样使用 use

$a = rand();
function () use ($a) {
  echo($a);
}

我非常感谢这一点,因为您会立即看到正在注入的变量,它没有像 js 中那样列在最底部:(function(b){})(a); 也没有过多的括号。我尝试使用.apply().call() 进行试验,但它们都执行该函数,我只想在某种状态下注入一个变量。

我想我只是要求一种不存在的语言功能,但请证明我错了。有什么想法吗?

【问题讨论】:

  • 每个人都提供了非常有价值的意见,我希望我能给你所有的分数。你们都展示了许多实现同一目标的方法,谢谢。
  • 带有this.x 的问题不再有任何意义,答案也不符合问题。

标签: javascript php scope closures


【解决方案1】:

使用 .bind() (ES5) 删除包装函数并避免关闭的简单方法:

function test(){
  return console.log.bind(console, Math.random());
}

【讨论】:

  • 谢谢。您已经证明有一种方法可以在没有闭包的情况下实现这一目标。我忘了绑定。
【解决方案2】:

你会用 es6 吗?如果是这样,箭头函数将给出相同的结果,但更简洁:

function test(){
	var x = Math.random();
  
	var printnum = x => () => console.log(x);
	return printnum(x);
  
    // OR you can invoke immediately:
    // var printnum = (x => () => console.log(x))(x);
    // return printnum;
}

var a = test();
var b = test();

a(); //number
a(); //same as above
b(); //different number
b(); //same as above

AFAIK,在 javascript 中,您必须以一种或另一种方式将 x 传递给函数,以避免在以后更改 x 的值时打印其他内容。

【讨论】:

  • 我给了你这个接受:'AFAIK,在 javascript 中,你必须以一种或另一种方式将 x 传递给函数'。谢谢你。 es6 的好例子。
【解决方案3】:

我个人喜欢 IIFE,但是“一个人的垃圾......”无论如何,你真的只需要传递一个数字的副本,这样你就不会陷入闭包变量中。

function test(){
  // Because you are working with a number and JavaScript passes all arguments by value
  // a copy of the number will be passed to helper, allowing helper to "disconnect"
  // from using the number in the parent scope
  return helper(Math.random()); 
  
  function helper(num){
    return function(){ console.log(num); }
  }
}

var a = test();
var b = test();

a(); //number
a(); //same as above
b(); //different number
b(); //same as above

【讨论】:

  • 感谢您的意见。我给了你一点。您演示了与 Crice 基本相同的过程,但使用的是 oldschool javascript。从本质上讲,没有办法摆脱闭包,只需明确声明您的范围而不使用包装函数构建范围。
  • @adjenks 这是正确的,也是为什么我说您必须复制该号码的原因。你无法规避 JavaScript 是词法作用域的事实,而词法作用域会导致闭包。
【解决方案4】:

不需要printnum 函数。只需返回内部匿名函数即可。

这本质上与 PHP 相同,但它不需要 use() 声明来列出要继承到闭包中的变量(PHP 需要这个,因为默认情况下不允许对外部变量进行任何访问)。

function test() {
  var x = Math.random();
  return function() {
    console.log(x);
  }
}

var a = test();
var b = test();

a(); //number
a(); //same as above
b(); //different number
b(); //same as above

【讨论】:

  • 谢谢你的例子。我忘记在我的示例中使用this.x 来演示我想在某个状态下捕获一个变量,并且该变量可能是静态的。我想你可以分配一个新变量,比如var y = x;,然后在函数中使用y
  • this.x 应该是什么?您的代码中不涉及任何对象。你是不是也想写new test()
  • 但是如果你使用new test(),它返回的是对象,而不是函数。所以不清楚你在修改后的问题中真正想要做什么。
  • 一切都是 Javscript 中的对象,哈哈。好吧,不是一切,但功能是。我只是给它一个静态属性用于演示目的。如果在示例中将 var x 替换为 this.x,它将重复相同的数字 4 次。
  • 你认为this在你的函数中指的是什么对象?如果调用test(),它指的是全局window 对象。您需要使函数成为某个对象(或其原型)的属性,然后将其称为someObject.test()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-23
  • 2021-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-03
相关资源
最近更新 更多