作用域
作用域的分类
-
全局作用域
在一个js脚本中,最外层的作用域就是全局作用域,在此范围内声明的任何变量都会是全局变量,可以在程序的任意位置访问 -
局部作用域
- 函数作用域
var locales = { school: function() { // 这里的school(学校)是局部作用域 var student = "公众号:搞前端的半夏"; var apartment = function() { //这里的apartment(宿舍楼)也是局部作用域 var room = function() { // 这里的room依然是局部作用域 console.log(student); // 公众号:搞前端的半夏 }; room(); }; apartment(); } }; locales.school(); //公众号:搞前端的半夏
我们想找到student,是怎么查找的呢,首先我们在他的宿舍查找,没有找到,然后会往上一层宿舍楼进行查找,宿舍楼没有找到,然后在往学校查找,最终找到了student。
- 代码块作用域
在代码块(if, for,while等等)中使用let和const声明变量,let和const会为这个代码块创建一个新的块级作用域。
function f(n) { if (true) { const msg = '你好'; let name = n; console.log(msg + " " + name); //公众号-搞前端的半夏 } console.log(msg + " " + name); //报错 msg is not defined } f('公众号-搞前端的半夏');
通过let和const在块级作用域外是无法被访问的。
function f(n) { if (true) { var msg = '你好'; var name = n; console.log(msg + " " + name); //公众号-搞前端的半夏 } console.log(msg + " " + name); //公众号-搞前端的半夏 }
当我们使用var关键字时,变量在整个函数作用域都是可访问的
在 JavaScript 中,可以在多层嵌套范围内指定同名变量。在这种情况下,局部变量优先于全局变量。如果你声明了一个同名的局部变量和一个全局变量,当你在函数或块中使用它时,局部变量将优先。
JavaScript 解释器从当时正在执行的最内层范围开始,一直持续到找到第一个匹配项,无论外层级别中是否存在其他同名变量。
var test = "我是全局";
function testScope() {
var test = "我是局部";
console.log (test);
}
testScope(); // output: 我是局部
console.log(test); // output: 我是全局
即使名称相同,局部变量在函数执行后也不会覆盖全局变量testScope()。
var test = "我是全局";
function testScope() {
test = "我是局部";
console.log(test);
}
console.log(test); // output: 我是全局
testScope(); // output: 我是局部
console.log(test); // output: 我是局部
这一次,局部变量test覆盖了同名的全局变量。当我们在testScope()函数内部运行代码时,全局变量被重新分配。如果一个局部变量在没有首先用关键字声明的情况下被赋值var,它就变成了一个全局变量。为避免此类情况,应始终在使用局部变量之前声明它们。在函数中使用关键字声明的任何变量var都是局部变量。
总结
- var 变量是函数作用域
- let and const 变量是块级作用域
- 使用var关键字声明的全局作用域变量属于window对象。
使用let关键字声明的全局作用域变量不属于window对象。 - var关键字定义的变量可以先使用后声明。
let关键字定义的变量需要先声明再使用。
const关键字定义的常量,声明时必须进行初始化,且初始化后不可再修改。
变量提升
var a = 1
function fn(){
console.log(a)
var a = 2
}
fn() //undefined
这个代码相当于
var a = 1
function fn(){
var a //undefined
console.log(a)
a = 2
}
fn() //undefined
变量声明提升
函数提升
function f() {
x();
function x() {
console.log(1);
}
}
f();
这个代码等价于
function f() {
function x() {
console.log(1);
}
x();
}
f();
扩展
var fn = function(){}和function fn(){}的区别:前者为变量提升,后者为函数提升。
fn1() //fn1
fn2() //fn2 is not function
function fn1() {
console.log("fn1")
}
var fn2 = function() {
console.log("fn2")
}
f();
如果是用变量提升来声明函数,如果在此前调用该函数,此时的函数对象并没有创建,变量fn2赋值为undefined,所以浏览器不能识别,把它当做函数来调用,所以最后报错。
在js中,函数优先级最高
被覆盖的不是函数fn,而是var fn =3;
console.log(fn)
function fn() {
console.log("hello world")
}
var fn = 1
结果