这个JavaScript代码的输出及原因。

4
function getCtr(){
  var i = 0;
  return function(){
    console.log(++i);
  }
}
var ctr = getCtr();
ctr();
ctr();

我已经使用JavaScript五年了,但在最近的一次面试中,这个问题让我感到十分困惑。我尝试了我所了解的一切,但是仍然无法弄清楚。

你能否帮助我找出问题的输出和原因,这样如果我有未来的面试,我就可以更好地准备。


2
它只是打印出了“1”和“2”,对吗? - Sam DeHaan
1
你期望的输出是什么? - Liviu T.
2
如果你想了解JavaScript闭包的工作原理,请阅读以下内容:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Closures - Luwe
8个回答

3
var ctr = getCtr();

这里调用了getCtr()函数,它会将i初始化为0,并存储对该函数的引用。
function() {
    console.log(++i)
}

在ctr中。因为该函数是在getCtr()的作用域内创建的,所以变量i仍然可以在存储在ctr中的函数的作用域内访问。

第一次调用

ctr()

执行了console.log(++i),它对i进行了前自增,因此打印出1。第二次调用执行相同的代码,使用相同的前自增,并打印出2

免责声明:我不是JavaScript开发人员。如果我犯了错误或使用了一些不受欢迎的措辞,请原谅。


1

所以你发布的代码输出 1 2。然而,这段代码:

function getCtr(){
  var i = 0;
  return function(){
    console.log(++i);
  }
}
getCtr()();
getCtr()();

仅输出 1 1

区别在于如果使用 var ctr = getCtr(); 保存 getCtr() 的引用,您将创建所谓的闭包。

因此,调用 getCtr()()ctr() 之间的区别在于,ctr 在其作用域中定义了 i,并且由于 var ctr = getCtr(); 保存了该作用域。因为引用被保存了,ctr 内部的函数能够始终对同一变量进行操作。


0

闭包

在那个函数中,return语句保存了i。因此,当仅调用var ctr = getCtr(); 时,var i = 0;变成了返回的函数:

function () {
       console.log(++i)
   }

变量 ctr 在外部函数 getCtr() 的作用域中具有 i,而返回函数也在 getCtr() 的作用域中。


0
当执行函数getCtr时,它会返回一个内部匿名函数。现在变量ctr引用了这个函数。由于匿名函数是在getCtr内部创建的,它将可以访问getCtr私有作用域对象,其中包含变量“i”。这被称为闭包
var ctr = getCtr()

每次执行匿名函数时,它都会对 i 进行预增操作,并将其写入控制台。
ctr()

0

让我们使用你可能从传统继承为基础的面向对象编程语言所了解的术语来细分它:

// In javascript functions are first-class objects
// This function is being used like a class would be in Java
function getCtr(){
    // You can think of this as a private variable of the getCtr "class"
    var i = 0;
    // Because it is returned, this is effectively a public method of getCtr
    return function(){
        // Which increments i and then prints it.   
        console.log(++i);   
    }
}

// This makes the variable ctrl an instance of getCtr.
var ctr = getCtr();
// This calls ctr's only public method.
ctr();
ctr();

因此输出将是“1, 2”。

这个问题的目的是测试您是否理解Javascript的原型继承,具有匿名函数闭包的能力。

一个更明确的版本将会做同样的事情:

var myProtoype = function() {
    var privateVariable = 0;
    var privateMethod = function () {
        privateVariable++;
        console.log(privateVariable);
    }
   return {
        publicMethod: privateMethod
   };
}

var myInstance = new myPrototype();
myInstance.publicMethod();
myInstance.publicMethod();

0

这个函数是一个Javascript模块。你可以在《Javascript: the Good Parts》中找到关于它的详细阅读,这是一本非常好的书籍,我强烈推荐。模块使用Javascript闭包来创建私有变量,如果被分配给一个var,那么每次调用该var时,它将保留它的变量而不是重新定义变量。

一个模块的工作方式如下:

function moduleName(privateVar1){
    var privateVar1;
    var privateVar2;

    return {
        exposedFunction1: function (var1) {
            // Do stuff... using private vars
            return something;
        },
        exposedFunction2: function (var1, var2) {
            // Do stuff...
            return something;
        }
    }
}

var moduleInstance = moduleName(privateVar1);
moduleInstance.exposedFunction(var1);

0

0

好的,getCtr是一个返回另一个函数的函数。 它还包含一个名为“i”的变量,其值设置为0。 “i”也可以在返回的函数的作用域中使用。 在将其记录到控制台之前对“i”进行预增量操作会导致每次调用存储在“ctr”中的返回函数时,“i”都会增加1。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接