所以我对js采访的问题基本上涉及内部函数中的范围和变量,例如假设你有这个:
function(){
var a=b=3;
}
显然,b没有被定义所以它已经成为一个全局变量,现在当你在全局范围内改变b时会发生什么变化呢?
我不确定如何测试这个,但是例如,如果你将b改为10,那么现在也是10还是会保持3?
答案 0 :(得分:8)
显然,
b
未定义,因此它已成为全局变量
仅在松散模式下。不要使用松散模式。 :-)使用严格模式,它应该是它应该存在的错误。
现在当您在全局范围内更改
b
时会发生什么,a
的值是否也会发生变化?
不,a
和b
之间根本没有链接。变量包含值(以下更多内容)。执行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 | +------------+
a
和b
具有相同的值,因此它们都指向同一个对象。
更改b
对a
仍然没有任何影响。人们感到困惑的是,如果我们更改了状态对象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);
,我们会看到一个着名的问题,因为a
和b
指向同一个对象。
如果我们实际更改了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的每个实现中,它不是一个多线程环境......