词法作用域,作用域链
1.函数声明和函数表达式的区别
function foo(){}
var foo=function(){}
1.上面的语法是声明,可以提升,因此在函数定义的上方也能调用该函数
2.下面的语法是函数表达式,函数名是foo,它会提升,提升的不是函数体
3.函数表达式也支持名字语法
function foo(){ } console.log(foo.name);//foo
**函数有一个属性name,表示的是函数名。函数声明的函数定义的属性值name就是该函数名,如果是函数表达式定义的函数定义,如果后面没有带函数名的,默认是函数表达式变量的值,如果后面带了函数名那么name属性值就是该函数名。函数声明能够直接使用name属性值,但是函数表达式不能在函数表达式之外使用函数的name属性,只能在函数表达式里面使用函数的name属性值。
//函数声明 function foo(){ }; foo.name;//结果是foo foo;//结果返回整个foo的函数体 //函数表达式 var foo1=function (){} //默认的是foo1.name就是foo1 var foo2=function bbb(){} //foo2.name就是bbb,但是这种函数表达式的函数定义的name属性值不能在外部直接使用。 //bbb //返回的bbb is not defined var foo3=function bbb(){ console.log(bbb); //这里能使用函数的name属性值 } foo3();//输出bbb的函数体
注意:
在新的浏览器中,包含在逻辑判断(if,while)里面的函数声明会被转换成特殊的函数表达式(函数声明的变量会提升,函数表达式的变量不会提升);
看一下例子
//如果是谷歌,火狐等主流浏览器 if(true){ function fun1(){console.log(123)} }else{ function fun1(){console.log(456)} } fun1();//结果123; if(true){ function fun1(){console.log(456)} }else{ function fun1(){console.log(123)} } fun1();//结果456; /*代码解析,按照javascript的预编译解析,一步一步走下来。因为函数声明包含在if这种逻辑判断里面,所以是特殊的函数表达式,不会发生变量提升。 if(true)->声明fun1,然后执行fun1,所以结果是输出123;*/ //如果是在IE8以下这种浏览器 if(true){ function fun1(){console.log(123)} }else{ function fun1(){console.log(456)} } /* 代码解析:包含在逻辑判断里面的函数声明还是函数声明,会发生变量提升,fun1声明,fun1覆盖前面这个声明 ,所以不管是条件是true或者是false,最后调用fun1()输出的结果都是456; */
2.词法作用域
*****
作用域:在js中出现域表示的就是范围,即作用范围。就是一个名字可以在什么地方使用,不可以在什么地方使用。
在c,java等语言中,花括号表示的是块级作用域
伪代码(仅仅用于描述意思即可)
{
var name=123;
{
console.log(name);//输出结果:123
}
}
console.log(name);//作用域之外访问name,表示的是name is undefined
******
词法作用域:所谓词法(代码)作用域,就是代码在编写过程中体现出来的作用范围,代码一旦写好了,没有运行之前(不用执行),作用范围就已经确定好了,这个就是所谓的词法作用域。
词法作用域的规则:
1.函数允许访问函数外部的数据
2.整个代码结构中只有函数才能限定作用域
3.作用规则首先使用变量提升规则分析
4.如果当前作用规则里面有该名字,则不考虑外面的外面的名字
if(false){ var num=123; } console.log(num); //undefined /* 代码说明:num变量发生了函数提升,首先定义了var num,但是由于false没有进入下面的var num=123的赋值操作,所以下面console.log(num)的时候显示undefined */
var num=123; function foo(){ var num=456; function func(){ console.log(num); } func(); } foo();//结果输出:456; /* 代码说明:首先最外面的num和foo发生了变量提升,执行foo()的时候,进入foo的作用域里面,num和func发生了变量提升,执行func()的时候,需要输出num,func里面没有num,需要外跳一级寻找num,如果这里面有num,则不查询外面的num了。 */
3.作用域链
绘制规则
(1)全局变量,函数申明都是属于0级链,每个对象占一个位置
(2)凡是看到函数就延伸一个链出来,一级级展开
(3)访问首先看到当前函数,如果当前作用域链没有定义,往上级链中检查
(4)如此往复,直到0级链,如果0级没有,则弹出错误,这个变量没有定义
var num=10; var func1=function(){ var num=20; var func2=function(){ var num=30; alert(num); }; func2(); } func1();//结果弹出:30
绘制作用域链,代码分析也标注在图上
以下这段代码值得好生体会一下:
function func1(){ alert(num); } function func2(){ var num=456; function func3(){ func1(); } func3(); } func2();//结果显示:num is not defined
绘制作用域链,代码步骤分析标注在图上