JavaScript中和C语言、Java这些语言不一样。在JavaScript当中,只存在函数作用域和全局作用域,而块级作用域是不存在的。刚刚接触JavaScript的话往往不知道这一点,所以很容易因为这一点在程序中出错。
作用域
JavaScript中作用域分为两种,分别是:
- 全局作用域
- 函数作用域
其中全局作用域指的是在一个**.js**文件中的作用域。全局作用域往往包含了这些特点:
- 变量公有化
- 函数公有化
简而言之就是说全局作用域中的变量和函数在这个**.js都是公有的、可访问的。而函数作用域**则比起它则范围相对狭小一些,特点为:
- 变量私有化
- 函数私有化
函数作用域当中的变量和函数都是私有的,任何对变量和函数的修改都只能在这个函数作用域内进行
提升
- 变量提升
由于我们上面所说的,JavaScript中没有块级作用域的存在,所以我们的每一个变量都是全局有效,或者是函数内有效。什么意思?我们先来看一下这段代码:
function gg(){
if(tag !== 'undefined'){
var tag = 'output!'
console.log(tag)
}
}
//输出: output!
复制代码
上面这段代码看似不可能输出output!,但是其实这里发生了变量提升。由于块级作用域不存在,所以代码var tag = 'output!'
在运行时发生了如下的情况:
function gg(){
var tag
if(tag !== 'undefined'){
tag = 'output!'
console.log(tag)
}
}
//输出: output!
复制代码
即变量tag的定义会被提升到作用域顶部,所以tag的初值为undefined
- 函数提升
和变量一样,函数也存在着提升的情况,有两种声明函数的方式:
- 函数声明:
function gg(){
console.log('success')
}
复制代码
- 函数表达式:
var gg = function(){
console.log('success')
}
复制代码
其中只有函数声明能够被提升到作用域顶部,而函数表达式这种形式声明的函数则不能被提升
console.log(f1) //输出 function f1(){}
console.log(f2) //输出 undefined
function f1(){}
var f2 = function(){}
复制代码
与之相关的题目
先来看下这段代码:
for(var i=1;i<6;i++){
setTimeout(function(){
console.log(i);
},1000);
}
//输出结果为: 6 6 6 6 6
复制代码
按照我们本来的意愿应该是让程序隔一秒后输出数字,分别是从1
到5
。但是现实是:隔了一秒以后输出5`个6。 前面提到的,js是存在变量提升的,那么由于变量i被提升为全局变量,所以后面输出的变量i其实是同一个i,循环结束后i变为6 那么如何写出自己想要的结果?这里提供几种方法:
- 方法1:绑定作用域,将关键字var改为let,具体代码为:
for(let i=1;i<6;i++){
setTimeout(function(){
console.log(i)
},1000)
}
复制代码
- 方法2:运用IIFE(立即执行函数),具体代码为:
for(var i=1;i<6;i++){
(function(j){
setTimeout(function(){
console.log(j)
},1000)
})(i);
}
复制代码
总结
JavaScript中只有两种作用域:全局作用域和函数作用域。而因为这个原因,在代码中的的函数声明、变量声明都会被提升到作用域顶部