一、作用域
1. 变量的作用域
- 变量的作用域就是变量的可作用范围
- 如果变量的作用范围是全局,这样的变量称为全局变量,在函数外部声明的变量就是全局变量
- 如果变量的作用范围仅限于某个函数,这样的变量称为局部变量,在函数内部声明的变量就是局部变量
- 函数中的形参和arguments是局部变量,作用域仅限于本函数
- 在函数内不使用var声明变量,被当做全局变量(严格模式下不允许这么做)
2. 作用域链
- 作用域链是如何产生的?
函数体内也可以声明函数,形成嵌套关系,有了上层作用域和下层作用域,形成了作用域 - 作用域链描述变量查找的过程
- 当时使用变量的时候,先看本作用域中有没有定义该变量,如果有定义直接使用
- 如果本作用域没有定义该变量,向上层作用域查找,如果没有继续向上层查找,哪里找到哪里停止,直到全局作用域
- 如果全局作用域仍然没有定义该变量,报错
- 从定义变量的角度看作用域链
变量只能在本作用域以及下层作用域被使用,不能被上层作用域使用
变量的组用域,只和函数声明的位置有关,与函数调用的位置无关!
二、变量提升和函数提升
1. 变量提升
- 代码正式执行之前,会进行遍历提升;使用 var 关键字声明的变量才会提升。
- 变量提升,只提升了变量的声明,并没有给变量赋值;
如果在变量声明语句之前使用变量,得到undefined;正式执行到变量声明语句,才会对变量赋值。 - 变量提升提升到所在作用域的最前面
console.log(userage); // undefined
var userage = 101;
console.log(userage); // 101
function func() {
console.log(email); // undefiend
console.log(userage); // undefined
var email = 'abc@qq.com';
var userage = 200;
console.log(email); // abc@qq.com
console.log(userage); // 200
}
func();
2. 函数提升
- function关键字形式声明的函数
- 整体提升,声明赋值一起提升
- 在函数声明语句之前,可以调用函数,因为是函数本身
- 正式执行到函数声明语句的时候,不会做任何操作
- 表达式方式、Function函数方式等需要使用var声明函数
- 同普通的变量提升没有区别
- 在函数声明语句之前,不能调用函数,因为是undefined
- 正式执行到变量声明语句的时候,再进行赋值
如果变量提升和function函数提升在一起
声明语句之前,函数提升因为声明赋值一起提升,但变量提升只有声明,所以可以简单理解函数提升更高级,输出的是函数本身
声明语句之后,正是因为函数提升声明赋值一起提升所以执行到声明语句不会有操作直接跳过了,而声明变量会进行赋值操作,所以输出变量
console.log(a); //undefined
console.log(fn);//[Function: fn]
console.log(demo);//undefined 提升了变量的声明,没有值
fn(); //可以调用
// demo();//无法调用
var a = 1
function fn() {
console.log('是fn');
}
var demo = function () {
console.log('demo');
}
三、预解析
变量和函数之所以会提升,是因为程序在代码执行之前会先进行预解析。
预解析遵循如下规则:
- 预解析先去解析函数声明定义的函数,整体会被提升。
- 再去解析带 var 的变量。
- 函数重名会覆盖,变量重名会忽略。
- 变量如果不带var,变量是不会进行预解析的;只有带var的变量才会进行预解析。
- 表达式方式和构造函数方式定义的函数也是当做变量去解析。