JavaScript传递引用如何解释这种行为?

时间:2017-11-28 20:54:06

标签: javascript

我是JavaScript新手,最近偶然发现了这个问题,质疑打印到控制台的内容。正确的答案是4 4 4 4,因为传递参考。但是,我不明白这是怎么回事。如果输出只是i的值似乎只依赖于for-loop的迭代,为什么传递引用会指示输出?

const array = [10, 21, 31, 41];

for(i = 0; i < array.length; i++) {
  setTimeout(function print(array){
      console.log(i)}, 3000);
}

4 个答案:

答案 0 :(得分:2)

好的,一步一步:

const array = [10, 21, 31, 41];

for(i = 0; i < array.length; i++) {
  setTimeout(function print(array) { /* stuff... */ }, 3000);
}

// When we get to here, the value of i is 4.

当此代码段运行时,我们迭代数组,并为每次迭代设置超时。当for循环结束时,我们调用了setTimeout四次,但没有给setTimeout赋予的函数。实际上,他们不会再跑3秒钟。

最重要的是,此时i的值为4

三秒钟后......

最后,我们向print提供的函数setTimeout将会运行。那么这个函数是什么样的?:

function print(array) { console.log(i); }

现在回想一下i的值现在是4.所以它打印4四次。这是因为当函数实际执行时,在声明函数时它会读取变量i而不是的值。

基本上,i在您实际调用函数print时为4,因此,打印4时不出所料。

答案 1 :(得分:1)

再次查看超时调用的内部函数。

public static  void main(String... args) throws Exception {

    String testJson = "{\"18\":{\"name\":\"poomba\",\"value\":\"topchoomba\"}}";

    Gson gson = new GsonBuilder().create();

    MyClassFor18 test18 = gson.fromJson(testJson, MyClassFor18.class);

    System.out.println(test18);

}

private static class MyClassFor18 {

    @SerializedName ("18")
    private TestPojo valueObject;

    public TestPojo getValueObject() {
        return valueObject;
    }

    public void setValueObject(TestPojo valueObject) {
        this.valueObject = valueObject;
    }

    @Override
    public String toString() {

        return "MyClassFor18 (value=" + valueObject + ")";
    }

}
private static class TestPojo {

    private String name;
    private String value;

    public TestPojo(String name, String value) {

        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {

        return "TestPojo { name=" + this.name + ", value=" + this.value
                + "}";
    }
}

传入的数组实际上并没有用于任何事情,实际上下面的代码会做同样的事情(打印4 4 4 4)

function print(array){
    console.log(i);
}

传递引用部分意味着它不是传递给print()函数的i的值,而是在控制台时调用i持有的任何值的引用.log(i)被调用。由于有3秒的延迟,循环有足够的时间完成,并且在第一个console.log(i)被调用时i的值是4。你甚至可以在循环后设置i的值,它会改变结果。

for(i = 0; i < array.length; i++) {
  setTimeout(function print(){
      console.log(i)}, 3000);
}

答案 2 :(得分:0)

你的setTimeout使你的代码异步,当3000的超时消失了javascript循环结束之前,索引的最后一个值也将是数字4.搜索'js Eventloop'你会发现更多关于,浏览器的工作原理简单。

答案 3 :(得分:0)

为了能够使用'i'值,你需要一个叫做闭包的东西。当函数执行时,i值变为4并且打印出来。