一、栈和堆

1、栈

基础数据类型:undefined、null、number、boolean、string、symbol 皆存放在栈中(闭包除外)
特点:大小固定,按值访问,可被用户直接操作

  1. let a = 1;
  2. let b = a;
  3. a = 100;
  4. console.log(b); // 1, b 不受 a 的影响

2、堆

引用数据类型:object、array、date、function 皆存放在堆中
特点:大小随机,按引用访问,不可被直接操作,用户表面上看似可以直接操作,但实际操作的是对其的引用

  1. let obj = {
  2. num1: 117
  3. } // obj 存放在栈中,且是个地址; {num1 : 117} 存放在堆中,是个对象

注意以下区分:

  1. let obj = {
  2. num: 1
  3. }
  4. let res = obj;
  5. obj.num = 0;
  6. console.log(res.num); // 0, obj 的指向和 res 为同一个堆中的数据, 一方更改另一方也会改
  1. let obj = {
  2. num: 1
  3. }
  4. let res = obj;
  5. obj = {num: 0};
  6. console.log(res.num); // 1, obj 被指向了一个新的对象, 因此对其的修改不会影响到 res

二、连等赋值

1、基础:从左到右声明变量,走右到左赋值
下面的代码:

  1. let a = b = 100;

实际上等同于:

  1. let a;
  2. b; // 相当于 var b
  3. b = 100;
  4. a = b;

2、进阶:局部变量中使用连等,会被提升至全局变量

  1. var a;
  2. var b;
  3. (function() {
  4. let a = b =1
  5. })();
  6. console.log(a); // undefined

实际相当于如下代码

  1. (function() {
  2. let a = 1;
  3. b = 1; // b 被提升至全局变量
  4. })();

三、两者结合的应用

  1. let obj = {
  2. num1: 117
  3. }
  4. let res = obj;
  5. obj.child = obj = { num2: 935 };
  6. var x = y = res.child.num2;
  7. console.log(obj.child); // undefined
  8. console.log(res.num1); // 117
  9. console.log(y); // 935

1、obj.child = obj = {num2: 935}

  • 1)、从左到右声明变量: ```javascript // 1、声明 obj.child, 原 obj 对象变为如下 let obj = { num1: 117, child: undefined }

// 2、声明 obj

  1. - 2)、 从右到左赋值
  2. ```javascript
  3. // 1. 为 obj 赋值
  4. let obj = {num2: 935}
  5. // 2. 为 obj.child 赋值, 注意这里的 obj 指的是原 obj 的地址, 而不是上一行刚被赋值的新的 obj
  6. let obj = {
  7. num1: 117,
  8. child: {num2: 935}
  9. }
  10. // 由于原 obj 的地址实际上是被 res 引用了,因此上面的代码可以理解为以下形式
  11. let res = {
  12. num1: 117,
  13. child: obj
  14. }

2、var y = res.child.num2

前面可以看出,res 其实就是 原 obj,且被赋予了新的属性 num2,因此可以正常输出