学习笔记(一):变量提升

变量提升

首先重申两个错误类型:

  • ReferenceError(引用错误):在作用域中找不到;
  • TypeError(类型错误):作用域中找到了,但是做了它不可能做的事情。
示例1:
console.log(fn); // ƒ fn () {}
console.log(a); // undefined
console.log(b); // ReferenceError: Cannot access 'b' before initialization
console.log(c); // ReferenceError: Cannot access 'c' before initialization
var a = 2;
let b = 2;
const c = 2;

function fn () {};

示例1的例子说明:

  • var声明的变量和函数会在任何代码执行前被处理,在初始化之前被提升到了当前作用域顶层,变量声明被默认先行赋值为undefined的值。let、const不存在变量提升。
  • var a = 2,会经历两个阶段:
    1. var a,这是在编译阶段进行的;
    2. a = 2,赋值声明会被留在原地等待执行阶段执行。
  • 先有声明,后有赋值.
示例2
console.log(fn); // ƒ fn () {}
console.log(a); // ReferenceError: a is not defined
function fn () {
  console.log(a);
  var a = 2
}

示例2的例子说明:

  • 每个作用域都会发生变量提升;
  • 变量提升只发生在当前作用域,而不是会提升到整个程序最上方。
示例3
console.log(fn()); // l am is fn
console.log(fn2()) // TypeError: fn2 is not a function

function fn () {
  console.log('l am is fn');
}
var fn2 = function () {
  console.log('l am is fn2');
}

示例3的例子说明:

  • fn2被提升并分配给所在作用域,但由于fn2是undefined,对undefined进行函数调用会抛出TypeError异常。
示例4
console.log(fn()); // l am is fn
console.log(fn3()); // ReferenceError: fn3 is not defined

function fn () {
  console.log('l am is fn');
};
var fn2 = function fn3() {
  console.log('l am is fn2');
};

是不是对fn3()的表现和异常提示有些奇怪,如果你发现了这个问题,说明离真相不远了。

示例4的例子说明:

  • 即使是具名函数,名称标识符(例如fn3)在赋值之前也无法在所在作用域中访问。
  • 回到示例1中所诉,赋值声明会被留在原地等待执行阶段执行。换句话说就是,具名函数在当前(全局)作用域中进行变量提升时,赋值操作不会进行提升。
  • 上面的例子经过提升实际会编译成下面这样:
    var fn2
    console.log(fn()); // l am is fn
    console.log(fn3()); // ReferenceError: fn3 is not defined
    function fn () {
      console.log('l am is fn');
    };
    fn2 = function () {
      var fn3 = ...
      ...
    };
    
示例5
var fn1

fn1() // l am is fn1 statement

function fn1 () {
  console.log('l am is fn1 statement');
}

fn1 = function () {
  console.log('l am is fn1 expression');
}
fn1() // l am is fn1 expression

示例5说明:

  • 函数优先。函数会首先被提升,然后才是普通变量;
  • var fn1的声明在function fn1之前,但是被忽略了。
  • 尽管如此,后面的声明仍然可以覆盖前面的(不建议这么写)。
示例6
fn() // TypeError: fn is not a function
var a = true
fn() // 3
if (a) {
  var fn1 = 2
  function fn () { console.log(1); }
  fn () // 1
} else {
  function fn () { console.log(2); }
}
// function fn () {
//  console.log(3);
// }
fn () // 1

示例6的例子说明:

  • 普通块内的函数声明会被提升到所在作用域的顶部;
  • 在普通块外部的同名函数声明会早于块内的同名函数声明,因此会导致,块内的函数覆盖块外的函数。

总结:

  • 变量和函数声明赋值操作,在js引擎看来是分为两个阶段的,一是编译阶段,提升就是发生在这个阶段,二是执行阶段。
  • 无论变量和函数声明在什么位置,都会被先“移动”到所在作用域的顶部,这过程称之为提升。
  • 声明本身会提升,但包括函数表达式赋值在内的赋值操作不会被提升。
  • 提升时的覆盖规则:
    1. 同名函数:后面的覆盖前面的;
    2. 同名变量:后面的会被忽略;
    3. 同名函数和变量:函数的提升会覆盖变量的提升。
  • 避免重复声明,会导致很多不必要的问题。

ps:文章中若发现错误请帮博主指正,感谢~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值