TypeScript 学习之var、let、const 的区别

var 关键字

JavaScript中,常用var声明一个变量。

语法

var varname1 [= value1] [, varname2 [=value2]] ...[,varnameN[= valueN]];
  • varnameN: 变量名。遵循命名规范
  • valueN: 变量的初始化值,可以是任何合法的表达式,默认值:undefined

描述

  • 变量声明,无法发生在何处,都在执行任何代码之前进行处理。

  • var声明变量的作用域是其当前的执行上下文。

  • 在任何函数外声明的变量为全局变量

  • 在函数内声明的变量为局部变量

  • 当赋值给未声明的变量时,执行赋值后,该变量会被隐式地创建为全局变量。(它将成为全局对象的属性)

  • 声明与未声明变量之间的差异:

    1. 声明变量的作用域限制在声明位置的上下文中。而非声明变量总是全局的。
    function x() {
      y = 1;
      var z = 2;
    }
    
    x();
    
    console.log(y); // 打印 1
    console.log(z); // 报错
    
    1. 声明变量在任何代码执行前创建,而非声明变量只有在执行赋值操作的时候才会被创建。
    console.log(a); // 抛出ReferenceError。
    console.log('still going...'); // 打印"still going..."。
    var a;
    console.log(a); // 打印"undefined"或""(不同浏览器实现不同)。
    console.log('still going...'); // 打印"still going..."。
    

    3.声明变量是其所在上下文的不可配置属性,非声明变量是可配置的(如非声明变量可以被删除)

    var a = 1;
    b = 2;
    
    delete this.a; // 在严格模式(strict mode)下抛出 TypeError,其他情况下执行失败并无任何提示。
    delete this.b;
    
    console.log(a, b); // 抛出 ReferenceError。
    // 'b'属性已经被删除。
    

变量提升

变量声明总是在任何代码执行之前处理的,所以在代码中的任意位置声明变量总是等于在代码开发声明。意味着变量可以在声明之前使用。这就是变量提升(hoisting)。

function do_something() {
  console.log(bar); // undefined
  var bar = 111;
  console.log(bar); // 111
}
do_something();

多个变量声明,初始化

// 多个变量声明,并初始化值为"A";

var a,
  b = (a = 'A');

隐式全局变量和外部函数作用域

var x = 0; // x 是全局变量,并且赋值为0

console.log(typeof z); // undefined 因为 z 还不存在,发生变量提升,初始化为 undefined

function a() {
  // 当 a 被调用时
  var y = 2; // y 被声明称函数a作用域的变量,然后赋值称2

  console.log(x, y); // 0 2

  function b() {
    // b 被调用时
    x = 3; // 全局变量 x 被赋值为3,不生成全局变量。
    y = 4; // 已存在的外部函数的y变量被赋值为4,不生成新的全局变量。
    z = 5; // 创建新的全局变量z, 并赋值为5。严格模式下,会报 `ReferenceError`
  }
  b();

  console.log(x, y, z); // 3 4 5
}

a(); // 调用 a 同时调用了 b
console.log(x, z); // 3 5
console.log(typeof y); // undefined 因为 y 是 a 函数的局部变量。

let

  • 用法与 var 用法一致,语义上有所不同
  • let声明一个变量,使用的是词法作用域块级作用域
  • 块级作用域变量:在包含他们的块或for循环以外是不能访问的。
function f(input: boolean) {
  let a = 100;

  if (input) {
    // a 可以访问
    let b = a + 1;

    return b;
  }

  return b; // error b 不能访问
}
  • 在 catch 语句里声明的变量也具有同样的作用域规则。
try {
  throw 'oh no!';
} catch (e) {
  console.log('Oh well.');
}

// Error: 'e' doesn't exist here
console.log(e);
  • 块级作用域的变量不能在声明之前读或写,虽然这些变量始终存在于“他们的作用域里”,但是直到声明他们的代码之前的区域都属于暂时性死区
a++; //illegal to use 'a' before it's declared; 在声明之前 a 是非法的。
let a;
  • 可以一个拥有块级作用域变量被声明前获取它, 只是不能在变量声明前去调用这个函数。
function foo() {
  return a;
}

// 不能在 `a` 被声明前调用`foo`
// 运行时应该抛出错误
foo();

let a;

重定义以及屏蔽

  • var 声明时,不管声明多少次,只会得到 1 个
// 所有x 的声明实际上都引用一个相同的x
function f(x) {
  var x;
  var x;

  if (true) {
    var x;
  }
}
  • let 声明时,同在一个作用域内不能声明相同的变量。
function f(x) {
  // error: interface with parameter declaration
  // 报错:属性已经声明
  let x = 100;
}

function g() {
  let x = 100;
  var x = 100; // error: can't have both declaration of 'x';
  // x 不能重复声明
}
  • 块级作用域变量需要在明显不同的块里声明
function f(condition, x) {
  if (condition) {
    let x = 100;
    return x;
  }
  return x;
}

f(false, 0); // return 0
f(false, 0); // return 100
  • 一个嵌套作用域引入一个行为称作屏蔽。(尽量避免使用屏蔽,可以用不同变量名)
// 内层循环的 i 可以屏蔽掉外层循环的 i
function sumMatrix(matrix: number[][]) {
  let sum = 0;
  for (let i = 0; i < matrix.length; i++) {
    var currentRow = matrix[i];
    for (let i = 0; i < currentRow.length; i++) {
      sum += currentRow[i];
    }
  }
  return sum;
}
  • let声明在循环体时,不仅引入一个新的变量环境,而且针对每次迭代都会创建一个新作用域。
for (let i = 0; i < 10; i++) {
  setTimeout(function () {
    console.log(i);
  }, 100 * i);
}

// 结果
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9;

const

  • let 拥有相同的作用域规则,但是不能重新赋值。
  • 声明是必须初始化。
const numLivesForCat = 9;
const kitty = {
  name: 'Aurora',
  numLives: numLivesForCat,
};

// Error 不能再次赋值
kitty = {
  name: 'Danielle',
};
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值