javascript范围引用变量

时间:2016-07-10 07:01:19

标签: javascript variables scope reference

所以我对js采访的问题基本上涉及内部函数中的范围和变量,例如假设你有这个:

function(){
var a=b=3;
}

显然,b没有被定义所以它已经成为一个全局变量,现在当你在全局范围内改变b时会发生什么变化呢?

我不确定如何测试这个,但是例如,如果你将b改为10,那么现在也是10还是会保持3?

2 个答案:

答案 0 :(得分:8)

  

显然,b未定义,因此它已成为全局变量

仅在松散模式下。不要使用松散模式。 :-)使用严格模式,它应该是它应该存在的错误。

  

现在当您在全局范围内更改b时会发生什么,a的值是否也会发生变化?

不,ab之间根本没有链接。变量包含(以下更多内容)。执行a = b后,b中的将复制到a。没有创建两个变量之间的链接。

面试官可能会问一个技巧问题(他们这样做很喜欢这样做)和/或他/她可能会陷入常见错误,所以请继续阅读...: - )

  

我不确定如何测试

由于我们处于松散模式,我们知道原始函数调用将设置this以在调用期间引用全局对象。由于隐式b全局将是全局对象的属性,我们可以通过更改this.b(全局)来检查它:

function foo() {
  var a = b = 3;
  console.log("(Before) a is " + a + ", b is " + b);
  this.b = 10;
  console.log("(After) a is " + a + ", b is " + b);
}
foo();

(在浏览器上我们可以使用window而不是this,因为window是引用全局对象的浏览器的默认全局。)

值得指出的是,虽然只有一个b,但上面对a的每次调用都会有不同的foo。但我认为这不会影响到这个问题。

在评论中,您询问了“参考变量”。 JavaScript中没有“引用变量”。您可能正在考虑对象引用。关键事实即将来临:对于我们所谈论的内容(将更改b更改a?),无论变量是包含对象引用还是基元,都没有区别。但这是人们常常犯的错误(可能甚至是面试官问的问题:-))认为这很重要。但是改变b(变量)改变对象b引用的状态会让人感到困惑。

变量包含。将对象引用分配给变量时,该对象引用是,它告诉javaScript引擎对象在内存中的位置。例如:

var b = {answer:42};

在记忆中,我们有:

                 +------------+
[b:REF55134]-----|  (object)  |
                 +------------+
                 | answer: 42 |
                 +------------+

b中的是对象的引用。我在上面将它表示为REF55134,但我们实际上永远无法访问该引用的原始值。原始值无关紧要,它只是告诉JavaScript引擎对象所在的东西(类似于一个数字)。

现在,如果我们这样做:

var a = b;

...我们将b复制到a,然后将其存入内存:


[b:REF55134]--+
              |   +------------+
              +-->|  (object)  |
              |   +------------+
[a:REF55134]--+   | answer: 42 |
                  +------------+

ab具有相同的值,因此它们都指向同一个对象。

更改ba仍然没有任何影响。人们感到困惑的是,如果我们更改了状态对象b指向,我们自然可以通过a看到更改状态。 b中的没有改变,它所指向的事物的状态发生了变化。

E.g:

b.question = "Life, the Universe, and Everything";

给我们:


[b:REF55134]--+
              |   +------------------------------------------------+
              +-->|                   (object)                     |
              |   +------------------------------------------------+
[a:REF55134]--+   | answer: 42                                     |
                  | question: "Life, the Universe, and Everything" |
                  +------------------------------------------------+

b没有改变,对象改变了。很自然,如果我们console.log(a.question);,我们会看到一个着名的问题,因为ab指向同一个对象。

如果我们实际更改了b,则它对a完全没有影响:

b = {foo:"bar"};
                  +------------+
[b:REF14359]----->|  (object)  |
                  +------------+
                  | foo: "bar" |
                  +------------+

                  +------------------------------------------------+
[a:REF55134]----->|                   (object)                     |
                  +------------------------------------------------+
                  | answer: 42                                     |
                  | question: "Life, the Universe, and Everything" |
                  +------------------------------------------------+

请注意,现在b中有一个不同的值,指的是另一个对象。

答案 1 :(得分:2)

在这种情况下,因为3是原始类型的数字。因此,它使用原始数据类型进行b分配和a分配。 JavaScript中的原始值定义不可变值。这意味着它所拥有的价值不会以任何方式从你身下发生变化。

这个问题虽然有点误导。如果每次调用函数时a正在更改,b的值将会不同。每次它是一个不同的变量a,但不一样。 a会立即超出范围,所以谁关心a?该函数等效于具有b = 3主体的函数。另外,在函数中修改任何类型的全局状态都是错误的设计。

ECMAScript 6定义了七种数据类型(布尔值,空值,未定义,数字,字符串,符号,对象),除了Objects之外,所有数据类型都是原始的。

在面试中明确提到你明白使用对象会有所不同,假设a没有立即超出范围。在这种情况下,更改b上的属性也会反映在a中。但完全更改b不会对a产生影响。为什么?因为当您更改属性时,您需要更改可变值,而不是变量。您可以更进一步说明使用包装器对象Number的工作方式也不同。

如果提及他提供的代码在严格模式下无效,您也会获得奖励积分。您可以使用文件顶部的"use strict";来指示您使用严格模式,或者也可以通过将严格模式作为函数中的第一个语句来限制函数。在ES6模块系统中,默认情况下会启用严格模式。

另一方面,由于a立即超出范围,问题非常严重,这可能表明一个糟糕的程序员面试你。在我所知道的JavaScript的每个实现中,它不是一个多线程环境......