作用域:标识符(变量和函数名)在那些地方能够被访问 哪些地方就是这个标识符的作用域,对于函数来说,这些地方就是指的 函数的代码块内部和代码块外部
(标识符:var fn;function fn;其中fn就是标识符)
规则1:函数内部的代码可以访问函数内部的标识符,也可以访问函数外部的标识符
规则2:函数外部可以访问函数外部的标识符,但是不能访问函数内部的标识符
通常函数内部的标识符为局部标识符
案例:
<script>
function fn () {
a=100 //未声明a,为a赋值,函数中找不到a,指向全局作用域下的a
//如果改为 var a = 100 ,则为局部变量,不是外部的a
}
var a=200;
fn()
console.log(a) //100
</script>
<script>
function fn (a) {
//隐式操作 var a=300 隐式声明了局部变量a
a=100 //为局部变量a赋值
console.log(a) //100
}
var a=200;
fn(300)
console.log(a) //200
</script>
<script>
function fn (a) {
//隐式声明形参a,并赋值实参给它 var a = 200
function fm (a) {
//隐式声明形参a,并赋值实参给它 var a = 200
console.log(a)// 200
a=90 //把a的值修改为90
console.log(a)//90
}
fm(a)//传入形参a,fm(200)
console.log(a)//虽然fm函数内作用域的a变化了,但是这里打印的是fn函数作用域内的a
//打印结果为200
}
var a=200;
fn(a)//fn(200)
console.log(a)//访问的是全局作用域下的a 200
//--------------------------------------------------------------------------------------
var a = 200;
function fn(a) {
//隐式声明形参a,并赋值实参给它 var a = 200
function fm() {
console.log(a)//打印a,fm函数中无a,到上一作用域中寻找a
//打印200
a = 90 //为a赋值,fm中无a,修改的是上一作用域中形参a
console.log(a)//90 //打印a,fm函数中无a,到上一作用域中寻找a
}
fm(a)//传入形参a,fm(200)
console.log(a)// 此时形参a的值已经被修改
//打印90
}
fn(a)//传入全局作用域下的a,fn(200)
console.log(a)//200
</script>
<script>
var total=0; //全局作用域下全局变量
function increment () {
var total=0 //increment函数内的局部变量
total=total+2
}
function decrease() {
total=total-2 //操作total,但是decrease函数内无total变量,修改的是全局变量total
}
//函数调用一边,内部代码执行一遍
increment()//total=0 + 2 //这里是局部变量total
increment()//total=0 + 2 //这里是局部变量total
decrease() //total=0-2 //这里是全局变量
console.log(total)//打印的是全局全局作用域下的total,无法访问函数内部的变量
//打印-2
</script>
标识符的隐式提升
每一个作用域在运行时,js引擎会先把作用域内部的关键字隐式提前扫描 并声明
函数也会隐式提升: 变量值提升声明,函数提升的是整个函数体
<script>
var a = 10//全局变量
function fn() {
//隐式声明var a,但是没有赋值
console.log(a)//打印变量a只是声明了但是没有赋值打印结果为undefined
a = 40//为a赋值
var a = 20//修改a的值
console.log(a)//打印结果为20
}
console.log(a)//打印全局变量,结果为10
fn()//调用函数
console.log(a)打印全局变量,结果为10
//----------------------------------------------------------------------------------
//fn函数隐式提升
fn() //调用 打印666
fm() //报错
function fn () {
console.log(666)
}
</script>
练习:
<script>
function fn (a) {
//隐式声明形参 var a=外部函数
//隐式提升函数fm
fm=a //从新赋值
//fm==>外部函数
function fm () {
console.log(124)
}
fm() //调用外部函数
}
var a=function() {
console.log(123)
}
fn(a)
</script>
注意:对象内部的方法不会隐式提升
<script>
function fn () {
console.log(obj.say) //找不到这个方法,报错
var obj={
say:function(){} //对象内部的方法不会隐式提升
}
}
fn()
</script>
同名标识符提升问题
变量名与函数名同名时:变量名先提升,函数再提升;
<script>
console.log(a) //打印a函数
var a=20
function a () {
console.log(100)
}
</script>
变量名与变量名相同时:先写先扫描(无意义)覆盖问题 就近访问
函数名与函数名相同时:先写先扫描,访问就近原则
<script>
function fn () {
console.log(111)
}
function fn () {
console.log(2222)
}
fn() //打印222
</script>
标识符的三种写法:
1、var a = 30;
2、function a(){}
3、function a(a){
//隐式操作:形参声明var a ;
}
实例:
<script>
var a=20
function fn(a){
//隐式操作声明形参:var a;
//隐式操作声明局部变量a :var a;
//把实参的值赋给形参:a=20;
//函数隐式提升
console.log(a)//打印函数a
a=90 //给a赋值为90
console.log(a)//90
var a=100 //把a的值改为100
console.log(a) //100
function a () {
console.log(6666)
}
console.log(a)//100
}
fn(a) //fn(20)
</script>
执行顺序口诀:形(形参和变量)实函运(巧记)
它的指,在一个作用域的代码运行的时候 js引擎会执行代码的过程只有一个执行流程
流程:
1、先隐式提升当前作用域内部的所有形参变量和局部变量(只是声明提升,不提升赋值)
2、再把实参赋值给形参变量
3、然后执行函数的隐式提前声明
4、再按照代码顺序运行代码
函数执行的作用域问题:
函数是一个引用数据,标识符可以在任何作用域去引用一个函数,但是函数运行时的作用域在函数生成时所在的作用域。
简单来说就是函数运行时,是在写函数代码的地方运行代码,不是在调用函数的地方运行代码
例子:
<script>
function fn(a) {
//隐式声明形参 var a;
//将实参的值赋值给形参 a=10
function fm() {
a = a + 1 //这里的a是fn函数内的形参a
console.log(a)
}
return fm
}
var f1=fn(10) //得到一个函数返回值 为fm函数
f1() //调用fm函数 打印11
//fm函数写在fn函数内,所有它的作用域在fn函数内,而不是调用的全局作用域下
</script>
<script>
function fn(a) {
//var a = 10
function fm() {
a = a + 1 //这里的a是fn函数内的形参a
console.log(a)
}
return fm
}
var f1=fn(10) //得到fm
f1()//调用 打印11
var f2=fn(10) //从新调用fn 代码从新执行一次
f2() //11
</script>