#hello,JS:03-02 声明提前和立即执行函数

一、声明提前

1、变量声明提前——变量提升

可参照这里的描述:

#hello,JS:01数据类型、运算符、运算符优先级

//先输出a,再声明
var a=3 
console.log(a) //undefined  
var a=3

再如:

console.log(a)//undefined 
console.log(b)  //报错 
 var a=3  

为什么console.log(a)输出undefined,而console.log(b) 则会报错呢?
出现这样的情况是为什么?实际上JS引擎在一行行执行代码的时候,有一些默认的运行我们并不知道,即:

var a   //undefined,变量a已经前置声明,则结果为undefined console.log(a) //undefined 
console.log(b) //报错,没有变量b,引用失败 
a=3  

最后是:变量的声明前置的完整运行:

var a     //undefined,已经前置声明为undefined 
console.log(a)     //undefined
 a=3 
console.log(a)  
--> undefined 3

2、函数的声明前置

先看这段代码:

sum(5,3) //放在任何的地方,但是只是一个函数值,并没有打印这个函数出来
function sum(a,b){
    return a+b
}

设置两种看两种执行结果:


image

看代码,不是没有任何的变量声明?为什么就可以使用函数输出结果?这是因为函数所执行的JS引擎默认操作与变量声明前置机制是类似。
相当于:包含变量数据的function函数前置,即以上代码等同于

function  sum(a,b){ 
            return a+b
    }  
      sum(5,3) 
 //直接返回8

3、函数表达式的声明前置

还是先看代码:

fn()
var fn = function(){
    console.log('fn...')
}
//报错,直接说fn不是一个函数

这里,function函数是一个变量,相当于把一个数字赋值给fn,而这个function函数表达式,事实上也是有一个声明前置的,即:

var fn   //undefined 
 fn()    //此为函数,会执行,但是如果是undefined(),这种是不成立,即报错
 fn =  function(){ 
          console.log('fn...') 
 }

那么原始代码是怎么执行的?
原始代码:

fn()  
sum(3,4) 
var fn =  function(){ 
           console.log('fn...')
    }  
           function  sum(a,b){ 
          return a+b
  }

对于浏览器来说它做了什么:一个声明前置:包括变量声明前置和函数声明前置

    var fn //变量声明前置  
             function  sum(a,b){ 
             return a+b }  //函数声明前置 
                 fn()  
                sum(3,4) 
                 fn =  function(){ 
                   console.log('fn...') 
         }

二、立刻执行的函数表达式

注:关于js的语法规则如何体现?

1、先看下面这个代码

              (function(){ console.log('wangxiaoqin')  })() 
 -->"wangxiaoqin"

先暂且不管它的结果如何产生。先了解一下JS的语法规则


image

按照这样写,为何只有function(){}单独作为一个变量时,通过模仿语句a( );function(){}();这个语句则会操作会报错,这是为什么?

对于JS引擎来说不认为是一个表达式,很像一个函数声明,再加一个括号,即会报错。那么如何让这个语句正常赋值?直接将整个函数声明加一个括号,即:

(function(){})()

由于作为运算符,括号和括号里的内容组合为一个表达式。加上括号之后,会让JS引擎认为它是一个表达式(或引用类型),那么就符合了JS的语法规则。

总结:
当在一个函数声明后加了圆括号(也是一种运算符)后运行的话,会报错。因为这被认为是语法错误。在JS中,以function开头会被认为是语句,而语句不应该以圆括号结尾。所以此时可以选用的解决办法是把整个语句用圆括号包起来。

2、那么刚才列举的代码:

(function(){ 
              console.log('wangxiaoqin')  })()
  -->"wangxiaoqin"  //即函数表达式,立刻去执行它
     
//等同于  
var fn =  function(){

   }  
     fn()

这类型的函数表达式有什么用?这里涉及了函数中所对应的作用域的概念,假设我们在这类函数里添加一个变量

          (function(){ 
              var a =3 console.log('wangxiaoqin') 
         })() 
          console.log(a)
//运行,后台报错,a是没有被定义的。 
 //因为a变量是不被看到的,因为a在function函数的这个作用域里,与外界无关

3、立刻执行函数的好处:

var fn=function(){}

相当于

fn()===(函数表达式)()

() 作为一种运算符,用这种局部作用域的方式将函数引用包裹起来,形成一个立即执行的表达式,好处在于:

A、函数不必再另外命名,避免了污染全局,不会在复杂页面协作中造成错乱;

B、实现一个作用域隔离,封装外部无法读取的私有变量;

C、避免命名冲突,符合js语法规则,并立刻执行。

三、命名冲突

当在同一个作用域内定义了名字相同的变量和方法的话,会根据前置顺序产生覆盖

var fn =  3; 
 function  fn(){
} 
console.log(fn); 
 // 3

相当于

var fn function  fn(){}  //覆盖上面的 fn =  3  //重新赋值 console.log(fn)  //为函数

当函数执行有命名冲突的时候,可以认为在还是内部一开始有隐藏的声明变量这个操作

function  fn(fn){
        console.log(fn); 
        var fn =  3; 
         console.log(fn); 
  }  
fn(10)  //10 3  

//等同于有一个默认的var fn = arguments[0]的操作 

 function  fn(){  
            var fn = arguments[0] //1、将它先声明前置,再赋值,再输出
          console.log(fn);  
          var fn =  3;  //2、再赋值
           console.log(fn);  
       }  fn(10) 

 //10  3

你可能感兴趣的:(#hello,JS:03-02 声明提前和立即执行函数)