es6基础(1)----let/const详细研究

let命令用于声明变量,其作用域限制在声明所在的代码块内,不会污染全局空间。与var不同,let声明的变量不会变量提升,存在暂时性死区。块级作用域使得变量管理更加清晰,避免了意外的全局变量和作用域污染。此外,文章还讨论了const常量声明、函数作用域以及对象冻结等概念。
摘要由CSDN通过智能技术生成

let命令,用来声明变量。

它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内{}有效。

{
  let a = 10;
  var b = 1;
}

console.log(a); //ReferenceError: a is not defined (引用错误)
console.log(b); //1

for (let index = 0; index < 10; index++) {}

console.log(index); //ReferenceError: index is not defined

变量i是var命令声明的,在全局范围内都有效

var a = [];
for (var index = 0; index < 10; index++) {
  a[index] = function () {
    console.log(index);
  };
}
a[1](); //10
a[6](); //10

如果使用let,声明的变量仅在块级作用域内有效

var a = [];
for (let index = 0; index < 10; index++) {
  a[index] = function () {
    console.log(index);
  };
}
a[1](); //1
a[6](); //6

for (let index = 0; index < 3; index++) {
  let i = "abc";
  console.log(i);
}

//abc
//abc
//abc

输出了 3 次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域 (同一个作用域不可使用 let 重复声明同一个变量)

console.log(foo); //undefined
var foo = 2;

console.log(bar); //ReferenceError: Cannot access 'bar' before initialization
let bar = 3;

//暂时性死区(TDZ)

var tmp = 123;

if (true) {
  // tmp = "abc"; //ReferenceError: Cannot access 'tmp' before initialization
  let tmp;
}

typeof x; //ReferenceError: Cannot access 'x' before initialization
let x;

typeof box; //'undefined'

变量一定要在声明之后使用,否则就报错。

 function bar(x = y, y = 2) {
   //ReferenceError: Cannot access 'y' before initialization
   //此时y还没有声明,属于死区
  return [x, y];
 }
 bar();

function foo(x = 1, y = x) {
  return [x, y];
}

foo();

/**
 * 这样就正常了
 */

 var x = x;
 let x = x; //ReferenceError: Cannot access 'x' before initialization



 function func() {
   let x = 10;
   var x = 2;
 }
 func(); //SyntaxError: Identifier 'x' has already been declared

 function func() {
   let a = 10;
   let a = 2;
 }

func(); //SyntaxError: Identifier 'a' has already been declared

 function func(arg) {
   let arg;
 }

 func(); //SyntaxError: Identifier 'arg' has already been declared

function func(arg) {
  {
    let arg;
  }
}

func();

总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,
但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量

块级作用域

var tmp = new Date();

function f() {
  console.log(tmp);
  if (false) {
    //似乎永远不会走这里,但是变量提升优先级最高
    /**
     * 原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。
     */
    var tmp = "hello world";
  }
}

f(); //undefined

var s = "hello";

for (var index = 0; index < s.length; index++) {
  const element = s[index];
  console.log(element);
}

变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。

console.log(index); // 5

// if (true) {
//   function f() {}
// }

function f() {
  console.log("I am outside!");
}

// (function () {
//   if (false) {
//     // 重复声明一次函数f
//     function f() {
//       console.log("I am inside!");
//     }
//   }

//   // f();   VM42:13 Uncaught TypeError: f is not a function
// })();

// const foo;  //SyntaxError: Missing initializer in const declaration

const a = [];

a.push("hello");

console.log(a);

// a = ["dave"]; //TypeError: Assignment to constant variable.

const foo = Object.freeze({});

foo.prop = 234;

console.log(foo);

const bar = {
  name: "珊姐",
  detail: {
    age: 18,
  },
};

const bar2 = Object.freeze(bar);

bar2.name = "力气";
console.log(bar); //{ name: '珊姐', detail: { age: 18 } }
bar2.detail.age = 30;
console.log(bar); //{ name: '珊姐', detail: { age: 30 } }

彻底冻结不让改

'var constantFreeze = (obj) => {
  Object.freeze(obj);
  Object.keys(obj).forEach((key, i) => {
    if (typeof obj[key] === "object" && obj[key] != null) {
      //递归冻结,不让改
      constantFreeze(obj[key]);
    }
  });
  return obj;
};
const bar3 = {
  name: "珊姐",
  detail: {
    age: 18,
  },
};
const bar4 = constantFreeze(bar3);

bar4.name = "张三";
console.log(bar4); //{ name: '珊姐', detail: { age: 18 } }
bar4.detail.age = 50;
console.log(bar4); //{ name: '珊姐', detail: { age: 18 } }

/**

  • es5声明变量的方式只有两种。var和function
  • es6声明变量的方式有四种,let const import class
  • 一共是6中声明变量的方式
    */
    顶层对象的属性与全局变量挂钩,被认为是 JavaScript 语言最大的设计败笔之一。
testA = 123;
console.log(global.testA); //nodejs中全局对象也是顶层对象,global,浏览器中是window

/**

  • 顶层对象与全局变量挂钩,被认为是javascript语言设计最大的设计败笔之一
  • why?
  • p1:没法在编译的时候报错变量未声明的错误,必须在运行时才知道
  • p2:容易不知不觉中创建了全局变量,打错字
  • p3:顶层对象的属性是到处可写,不利于模块化工程
  • P4:window对象是有实体含义的,指的是浏览器的窗口对象,顶层对象是一个有实体含义的对象,也是不合适的
    */

/**

  • ES6 为了改变这一点,一方面规定,
  • 为了保持兼容性,var命令和function命令声明的全局变量,
  • 依旧是顶层对象的属性;
  • 另一方面规定,let命令、const命令、class命令声明的全局变量,
  • 不属于顶层对象的属性。也就是说,
  • 从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
    */
console.log(globalThis);

 * <ref *1> Object [global] {
  global: [Circular *1],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  testA: 123
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值