原文链接:https://hackernoon.com/unders...
什么是作用域?
就像JavaScript中的其他东西一样,作用域并无特别之处。尽管大多数开发者并不会在上面太多时间,不过,深入理解作用域有助于你写更干净的应用,也有助于降低错误和实现更好的设计模式。
作用域是代码的不同部分在运行期间的可见性。
大多数开发者想当然地理解作用域,但毫无疑问,JavaScript有它自己的说明。变量可能是全局作用域的,或者是方法作用域的。这也就意味着,变量存在于任何地方都能被访问的全局,或者存在于声明它们的方法之内。
var global = 'I am global scoped'
function testingFunctionScope() {
var global = 'I am function scoped';
console.log(global); // I am function scoped
}
testingFunctionScope();
console.log(global); // I am global scoped
正如你在例子中看到的那样,尽管全局变量在方法内被赋予一个不同的值,但它只保存在这个方法中。在方法外面,那个变量有一个不同的值---在全局作用域声明的值。
var global = 'global'
var anotherGlobal = 'also global'
function functionScope () {
var global = 'function scope'
console.log(global) // function scope
var scoped = 'also function scope'
function inner () {
console.log(scoped); // also function scope
console.log(anotherGlobal) // also global
}
inner();
}
console.log(global) // global
console.log(anotherGlobal) // also global
console.log(scoped) // ReferenceError
functionScope();
inner(); // ReferenceError
这是一个拥有内部函数的例子,并展示了它如何访问父作用域的变量。正如父函数 functionScope()
那样 ,它内部声明的每个变量只在其内部和它的内部函数中有效。
注意:绝对不要使用未声明的变量 如果那样做了,引擎会冒泡到父作用域寻找此变量。如果寻之不得,js会为你声明一个。这样你无意之中就创建了一个全局变量并扰乱了全局作用域。
另外,未定义和未声明不是同一件事情。未定义:声明了一个变量但没有赋值,未声明:变量根本还没有被声明。
好了,到目前为止,没有什么特别之处,且看下面代码如何返回:
test(); // ???
function test() {
console.log('working?!');
}
惊不惊喜?确实打印出了 working?!
。为了理解其中缘由我们必须探求JavaScript另一个概念。
变量提升
在此我将不同于他人,我会描述什么是变量提升并解释其弊端。困惑?好-Javascript就应该困惑。变量提升这种奇怪的行为,意味着你可以在方法声明前调用它。
在JavaScript中,代码执行之前变量和方法会被移至顶端。所以上面奇怪的代码判断,实际上变成:
function test() {
console.log('working?!');
}
test(); // working?!
因此,我们写的和实际执行的并不一致。变量定义也是一样---它们都会提升到自己作用域的顶部(用var关键字声明的会;用let声明的则不会)。变量的声明会提升,赋值并不会。所以如果我们在一个变量赋之前使用它,得到的是undifined,并不是错误
var test;
console.log(test) // undefined
test = 'working?'
console.log(test) // working?
所以使用函数表达式的时候千万小心,因为只有函数的声明提升了。我们现在对JavaScript中的的作用域和变量提升有了基本的理解,实际上两者有很大不同。JS代码的整个执行过程非常不同,并且变量提升也并非大多说人所想。这更多的是我们持有的精神概念。
编译
出乎意料,JavaScript确实需要编译。V8引擎在执行前通过将JavaScript编译成本地机器码而不是执行字节码或解释它来提升性能。实际上引擎会多线程运行代码。其中一个线程,负责声明所有方法和变量,所以在运行时都已存在。虽然解释编译过程更加简单,对于变量提升我们创建了在代码运行前如何组织代码的思维导图。
简言之---在JS代码实际执行前,引擎已经运行了整个脚本并在它们的作用域中声明了所有的变量和方法。所以在运行时,它们已经存在,变量提升并非什么黑魔法。如果你理解了这个,你就超过了其他90%的JavaScript开发者。
总结
JavaScript的作用域还有很多需要学习。为了缩短篇幅让大家有个基本的理解,我甚至都没有提LHS和RHS。如果你搞不清楚你所做的事情,JavaScript绝对惊喜多多(bug啊)。总而言之,不要重复声明变量,使用良好命名,尽力避免在声明前调用和执行任何东西。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。