1. 定义:
变量可以起作用的范围
作用域分为全局作用域和局部作用域(私有作用域)
2. 全局作用域:
script 标签内就是全局作用域,在全局中都可以使用。
生命周期: 从页面打开到页面关闭
全局作用域中定义的变量,在全局中都可以使用。
注意:在 JS 中, 全局作用域中有一个 提前给我们准备好的 window对象,创建的全局变量, 会被自动添加到 window 对象中。
<script>
var num =100;
function fn() {
console.log( num );
}
fn();
console.log( num )
</script>
3. 局部作用域:(以下规则:仅针对于var这个关键字)
也叫做私有作用域,在js中只有函数的大括号才能确定一个局部作用域(if和for的大括号不行)
在局部作用域中定义的变量,只能在这个局部作用域中使用,在别的地方不能使用
<script>
局部作用域
function ff() {
var abc123 = '我是在 fn 函数内部创建的局部变量'
}
function ff2() {
var abc123 = '我是在 fn 函数内部创建的局部变量'
}
</script>
案例1
<script>
var num = 100;
function fn() {
console.log( num ); // undefined
var num = 200;
console.log( num );// 200
var username = 'zs';
}
fn(); // undefined 200 100 报错 username is not defined
console.log( num ) // 100
函数私有作用域定义的变量,在外部补不能使用
console.log( username) // 报错 username is not defined
</script>
// 执行解析:
// fn函数调用,fn函数内有预解析 变量提升
// fn函数内:
function fn(){
var num;
var username;
console.log( num );
num = 200;
console.log( num );
username = 'zs';
}
// 1. 在函数的私有作用域中声明了变量num和username没有赋值
// 2. 在私有作用域中访问变量num,私有作用域中声明了这个变量,但是还没有赋值,所有输出是undefined
// 3. 将数值200赋值给私有作用域中的变量num
// 4. 在私有作用域中访问变量num,私有作用域中声明了这个变量,并且值为200,所以输出200
// 5. 将字符串'zs'赋值给私有作用域中的变量username
4. 作用域链
会先在当前自己作用域中查找,是否有定义这个变量,如果有则拿来使用
如果当前作用域中没有这个变量,则去上一父级作用域中查找,找到了则使用
如果找不到,则再继续去上一父级作用域中查找这个变量,找到了则使用
如果还是找不到,则再继续去上一父级作用域中查找这个变量,找到了则使用
.....
一直往上级作用域中查找,直到全局作用域查找,找到则使用
如果在全局作用有中还是找到不到,则报错(变量 is not defined)
我们将这个一层一层向上查找的规律, 叫做作用域链
注意: 变量的访问,找不到的时候只会去上一级作用域查找,不会往下的作用域中查找
5. 作用域中变量的赋值规则 和 隐式全局变量
作用域中变量的赋值规则:
当作用域中有 给变量赋值的时候,
会现在当前作用域中找,是否有声明这个变量,如果有声明则赋值
如果没有,则去上一级作用域中查找,在上一级作用域中是否有声明这个变量,如果有则赋值
如果还是没有,则继续往上一级作用域中找,如果还是没有,则继续往上的作用域中找
如果直到这种作用域找,还是没有找到,则会将这个变量定义为 **全局变量** ,并且赋值
这种定义的变量 我们称之为 隐式全局变量
<script>
function fn1() {
var num = 999
function fn2() {
num = 100
/**
* 在当前作用域内查找 num 发现没有, 会去自己的父级作用域内查找, 也就是 fn1 函数内部
*
* 在 fn1 函数内部发现一个变量 num 然后值为 999 我们会对这个变量做一个重新赋值的操作
*
* 也就是将他的值 重新修改为 100
*/
}
fn2()
console.log(num) // 100
}
fn1() // 100 报错num is not defined
console.log(num) // 报错num is not defined
</script>
<script>
var num = 666
function fn1() {
var num = 999
function fn2() {
num = 100
/**
* 在当前作用域内查找 num 发现没有, 会去自己的父级作用域内查找, 也就是 fn1 函数内部
*
* 在 fn1 函数内部发现一个变量 num 然后值为 999 我们会对这个变量做一个重新赋值的操作
*
* 也就是将他的值 重新修改为 100
*/
}
fn2()
console.log(num) //100
}
fn1() //100
console.log(num) // 666
</script>
<script>
var num = 666
function fn1() {
function fn2() {
num = 100
/**
* 在当前作用域内查找 num 发现没有, 会去自己的父级作用域内查找, 也就是 fn1 函数内部
*
* 在 fn1 函数内部, 发现没有 这个变量, 继续去自己的父级作用域查找, 也就是 全局作用域
*
* 在全局作用域发现了一个变量 叫做 num, 他的值是 666, 我们将这个变量重新赋值为 100
*/
}
fn2()
}
fn1()
console.log(num) // 100
</script>