词法作用域,作用域链

Posted 愿一切美好都如期而至

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了词法作用域,作用域链相关的知识,希望对你有一定的参考价值。

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

绘制作用域链,代码步骤分析标注在图上

 

以上是关于词法作用域,作用域链的主要内容,如果未能解决你的问题,请参考以下文章

JS高级. 05 词法作用域变量名提升作用域链闭包

markdown 动态作用域词法作用域作用域作用域链执行环境

javascript 之作用域链-10

词法作用域,作用域链

理解闭包

JS基础之——作用域和作用域链