1.作用域
作用域:标识符(变量和函数名) 在函数的代码块内部和函数的代码块外部能够被访问 函数的代码块内部和函数的代码块外部就是这个标识符的作用域
规则:
1):函数内部的代码可以访问函数内部的标识符,也可以访问函数外部的标识符(副作用)
2):函数外部可以访问函数外部的标识符,但是不能访问函数内部的标识符
总结:
1)通常称函数内部的标识符为局部标识符
2)函数内部为声明的变量为全局变量 如:a=40
案例:
var total = 0;
function increment() {
var total = 0
total = total + 2
console.log(total)
}
increment()//{var total=0; total = total + 2}
increment()//{var total=0; total = total + 2}
分析: 函数的调用是运行一次代码:每一次调用都会重新执行所有代码,每次调用都会重新声明
var total = 0,因此每次调用的结果为2
2.同名标识符的提升(提前声明)问题
提升:每一个作用域在运行时,js引擎会先把作用域内部的关键字隐式提前扫描 并声明
2.1 函数隐式提升
函数也会隐式提升: 变量值提升声明,函数提升的是整个函数体
fn()
function fn () {
console.log(666)
}
分析:
1.隐式提升函数 function fn () { console.log(666) }
2.正常运行代码fn()
2.2 案列
案例:
function fn (a) {
//var a=外部函数
//funn fm()
//fm==>外部函数
fm=a
function fm () {
console.log(124)
}
fm()
}
var a=function() {
console.log(123)
}
fn(a)
分析:在function fn (a) 内部,先隐式声明外部传入的值var a=外部函数 然后提升函数function fm (),fm=a将fm函数改为a函数,fm()调用时的函数为function() { console.log(123) }
2.3 对象内部的方法不会隐式提升
function fn () {
console.log(obj.say)
var obj={
say:function(){}
}
}
fn()
3.同名标识符提升问题
3.1同名标识符提升问题:变量函数同名时
1)变量函数同名时:先变量后函数
2)案列
console.log(a)
var a=20
function a () {
console.log(100)
}
console.log(a)
分析:
1.先提前声明变量var a
2.再提前声明函数function a () { console.log(100) }
3.console.log(a) a=20 console.log(a)
3.2 同名标识符提升问题:变量和变量同名时
1)变量和变量同名时:先写先提升,后写后提升,运行时就近原则
2)案列:
console.log(a)//unf
var a=10;
console.log(a)//10
var a=20;
console.log(a)//20
分析:
1.提升变量var a;var a;
2.console.log(a)//undef
3.a=10;
4.console.log(a)//10
5.a=20;
6.console.log(a)//20
3.3 同名标识符提升问题:函数和函数同名时
1)函数和函数同名时:先写先提升,后写后提升,运行时就近原则
2)案列:
function fn () {
console.log(111)
}
function fn () {
console.log(2222)
}
fn()
分析:
1.提升函数 function fn () { console.log(111) } function fn () { console.log(2222) }
2.fn()调用,就近原则,最后一次声明的fn函数为function fn () { console.log(2222) }, 调用function fn () { console.log(2222) }
4.综合案列及执行流程
4.1 执行流程(口头说法形(形参和变量)实函运)
流程:
1.先隐式提升当前作用域内部的所有形参变量和局部变量 (只是声明提升,不提升赋值)
2.再把实参赋值给形参变量
3.然后执行函数的隐式提前声明
4.再按照代码顺序运行代码
4.2 综合案列
var a=20
function fn(a){
console.log(a,1)//函数
a=90
console.log(a,2)
var a=100
console.log(a,3)
function a () {
console.log(6666)
}
console.log(a,4)
}
fn(a)
分析:
1.提升变量var a;
外部传入的值a=20
提升函数function a () { console.log(6666) }
console.log(a,1),打印函数
2.给变量a赋值a=90
console.log(a,2)//打印90
3.给变量a赋值a=100
console.log(a,3)//打印100
4.a函数没调用 console.log(a,4)//访问变量a打印100
5.函数运行时的作用域
5.1
1)函数运行时的作用域在函数生成(定义和声明)时所在的作用域
2)函数运行时是在写函数代码的地方运行代码,不是在调用代码的地方运行代码
5.2 案列
1)案列1
function fn(a) {
function fm() {
a = a + 1
console.log(a)
}
return fm
}
var f1=fn(10)
f1()
f1()
分析: f1()==>fm()
{
var a//提升形参
a=10///传入实参
return fm
a=11//第一次运行后a的值为11
a=12
第一次运行
{
a = a + 1//a在自己作用域内没有,访问外部a=10 a=10+1
console.log(a)//11
}
第二次运行
{
a = a + 1
console.log(a)//a在自己作用域内没有,访问外部a=11 a=11+1
}
}
2) 案列2
function fn(a) {
function fm() {
a = a + 1
console.log(a)
}
return fm
}
var f1=fn(10)
f1()
var f2=fn(10)
f2()
分析: var f1=fn(10) f1() ,var f2=fn(10) f2() 表示声明的是两个变量
f1()---fm()
{
var a//提升形参
a=10//传入实参
return fm
{
a = a + 1
console.log(a)////a在自己作用域内没有,访问外部a=10 a=10+1
}
}
f2()---fm()
{
var a//提升形参
a=10//传入实参
return fm
{
a = a + 1
console.log(a)////a在自己作用域内没有,访问外部a=10 a=10+1
}
}