javascript的几个知识点scoping,execution context, hoisting, IIFE

 JavaScript 属于解释型语言,JavaScript 的执行分为:解释和执行两个阶段,这两个阶段所做的事并不一样:

解释阶段:

  • 词法分析
  • 语法分析
  • 作用域规则确定

执行阶段:

  • 创建执行上下文
  • 执行函数代码
  • 垃圾回收

Hoisting--提升

Hoisting的发生范围是函数作用域(function-local scope)。在函数内var定义的变量和函数声名会被提升到该函数作用域的上面。function内的提升的顺序所下:

  1. this, arguments
  2. 形参 formal parameters
  3. 函数声名 function declarations
  4. 变量声名 variable declarations

举例:

var a = 1;

function test(){
  if(!a){
  var a = 5;  
 }  
console.log(a);
}

test();
//打印出5这

这是因为当解析器读到if语句时,发现有一个变量声名和定义:var a = 5;于是解析器就把这个变量的声名:var a;提到当前作用域的顶部。上面的代码最后执行是其实是这样的

var a = 1;

function test(){
  var a;
  if(!a){
  a = 5;  
 }  
console.log(a);
}

test();

 如果想打印出1的话,需要用let来定义块级变量: let a =5;或者把var a = 5放到一个立即执行函数里。

再举一个函数提升的例子

function test(a){
  if(!a){
   var a = 5;  
 }  
 function a(){}//function declaration
 console.log(a);
}

test(0);
//打印出function a(){}

  执行的实际代码如下

function test(a){
 function a(){}
 var a;
  if(!a){
   a = 5;  
 }  

 console.log(a);
}

test(0);
//打印出function a(){}

  如果代码做以下修改

function test(a){
  if(a){
   var a = 5;  
 }  
 function a(){}
 console.log(a);
}

test(0);
//打印出5

  因为a被重新赋值了。

function test(a){
  function a(){}
  var a;
  if(a){
   a = 5;  
  }  
 console.log(a);
}

test(0);
// if(a)一直是 true,打印出5

  

声名变量var a,只是让解释器知道有这个a的存在,a到底是什么,就需要对变量进行定义:a=5。如果再给a赋值:a = function(){},那a又被定义为了函数。a到底是什么是由定义来决定的。定义的是什么,输出的就是什么。不为因为再次的声名而改变。如果用函数表达式来定义函数,会出现什么情况:

function test(){
  b();
  var b = function (){}
}
test()
//会报错“undefined is not a function”

  函数表达式时,只用变量名被提升,它定义的函数体依然留在原处。执行的代码是这样的

function test(){
  var b;
  b();
  b = function (){}
}
test()

 只对b做了声名,而没有定义,所以执行到b()会报错。

Scoping--作用域

ES6之前只有函数作用域。ES6加入块级作用域。用let声名的变量是块作用域内有效,用var声名的变量在函数作用域与块作用域里有效。

 

作用域链

作用域内取值是从创建该函数的位置取值,而不是从调用该函数的位置取值。

  https://yq.aliyun.com/articles/693736

Execution Context 执行上下文

执行上下文是在执行过程中产生的。

https://juejin.im/post/59e85eebf265da430d571f89?spm=a2c4e.11153940.blogcont685883.21.727f127e0QVeWU

作用域和执行上下文之间最大的区别是:
执行上下文在运行时确定,随时可能改变;作用域在定义时就确定,并且不会改变 

IIFE(Immediately Invoked Function Expression)

形式有多种:

(function(){ cosole.log(1); })()

(function(){ console.log(1);}())

+function(){console.log(1);}()

!function(){console.log(1);}()

void function(){console.log(1);}()

这样写是编译不过去的:function(){console.log(1);}()

顾名思义,immediately invoked function expression,是被解析成为一个函数表达式,然后自执行。

立即调用函数有个超强的用法,模块模式,如下

var counter = (function(){
    var i = 0;
    return {
        get: function(){
            return i;
        },
        set: function(val){
            i = val;
        },
        increment: function(){
            return ++i;
        }
    }
    }());
    counter.get();//0
    counter.set(3);
    counter.increment();//4
    counter.increment();//5

  想要扩展counter的方法:

var counter = (function(c){
    c.ext= function (){
        console.log('extend');
    }
     return c;
    }(counter || {}));
counter.ext();

  

 

 

refer: http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.htm

https://yuiblog.com/blog/2007/06/12/module-pattern/

http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html

http://www.cnblogs.com/TomXu/archive/2011/12/30/2288372.htmll

posted @ 2019-02-14 15:30  被爱浸润的智慧体  阅读(239)  评论(0编辑  收藏  举报