# 变量提升

  • 函数声明高于变量声明
var b = 10;
(function b() {
   // 内部作用域,会先去查找是有已有变量b的声明,有就直接赋值20,确实有了呀。发现了具名函数 function b(){},拿此b做赋值;
   // IIFE的函数无法进行赋值(内部机制,类似const定义的常量),所以无效。
  // (这里说的“内部机制”,想搞清楚,需要去查阅一些资料,弄明白IIFE在JS引擎的工作方式,堆栈存储IIFE的方式等)
    b = 20;
    console.log(b); // [Function b]
    console.log(window.b); // 10,不是20
})();

# IIFE

IIFE( 立即调用函数表达式)是一个在定义时就会立即执行的 JavaScript 函数。

  (function () {
    statements
  })();

这是一个被称为 自执行匿名函数 的设计模式,主要包含两部分。第一部分是包围在 圆括号运算符 () 里的一个匿名函数,这个匿名函数拥有独立的词法作用域。这不仅避免了外界访问此 IIFE 中的变量,而且又不会污染全局作用域。

第二部分再一次使用 () 创建了一个立即执行函数表达式,JavaScript 引擎到此将直接执行函数。

# 访问内部值/外部值

var b = 10;
(function b(){
    var b = 20; //or let b = 20;
	  console.log(this)
    console.log(this.b); //10
    console.log(b);  //20
})();

或者可以通过在调用IIFE时传入参数。

    var b = 10;
    (function b(b){
		    console.log(window)
        console.log(window.b); //10
        b = 20;
        console.log(b);  //20
    })();

# 试一试

var a = 10;
(function () {
    console.log(a)
    a = 5
    console.log(window.a)
    var a = 20;
    console.log(a)
})()
  • 在立即执行函数中,var a = 20; 语句定义了一个局部变量 a,由于js的变量声明提升机制,局部变量a的声明会被提升至立即执行函数的函数体最上方,且由于这样的提升并不包括赋值,因此第一条打印语句会打印undefined,最后一条语句会打印20。
  • 由于变量声明提升,a = 5; 这条语句执行时,局部的变量a已经声明,因此它产生的效果是对局部的变量a赋值,此时window.a 依旧是最开始赋值的10,
var a = 10;
(function () {
    console.log(a)
    a = 5
    console.log(window.a)
    a = 20;
    console.log(a)
})()

10,5,20

总结:

  • 自执行函数会形成块级作用域
  • 作用域链是自内向外查找
  • 作用域形成与js引擎编译阶段,并不会做赋值操作
  • var声明的全局变量会赋值给window对象
var name = 'Tom';
(function() {
if (typeof name == 'undefined') {
  var name = 'Jack';
  console.log('Goodbye ' + name);
} else {
  console.log('Hello ' + name);
}
})();
var name = 'Tom';
(function() {
if (typeof name == 'undefined') {
  name = 'Jack';
  console.log('Goodbye ' + name);
} else {
  console.log('Hello ' + name);
}
})();

参考:

Last Updated: 2/19/2020, 12:38:17 PM