一、栈和堆
1、栈
基础数据类型:undefined、null、number、boolean、string、symbol 皆存放在栈中(闭包除外)
特点:大小固定,按值访问,可被用户直接操作
let a = 1;
let b = a;
a = 100;
console.log(b); // 1, b 不受 a 的影响
2、堆
引用数据类型:object、array、date、function 皆存放在堆中
特点:大小随机,按引用访问,不可被直接操作,用户表面上看似可以直接操作,但实际操作的是对其的引用
let obj = {
num1: 117
} // obj 存放在栈中,且是个地址; {num1 : 117} 存放在堆中,是个对象
注意以下区分:
let obj = {
num: 1
}
let res = obj;
obj.num = 0;
console.log(res.num); // 0, obj 的指向和 res 为同一个堆中的数据, 一方更改另一方也会改
let obj = {
num: 1
}
let res = obj;
obj = {num: 0};
console.log(res.num); // 1, obj 被指向了一个新的对象, 因此对其的修改不会影响到 res
二、连等赋值
1、基础:从左到右声明变量,走右到左赋值
下面的代码:
let a = b = 100;
实际上等同于:
let a;
b; // 相当于 var b
b = 100;
a = b;
2、进阶:局部变量中使用连等,会被提升至全局变量
var a;
var b;
(function() {
let a = b =1
})();
console.log(a); // undefined
实际相当于如下代码
(function() {
let a = 1;
b = 1; // b 被提升至全局变量
})();
三、两者结合的应用
let obj = {
num1: 117
}
let res = obj;
obj.child = obj = { num2: 935 };
var x = y = res.child.num2;
console.log(obj.child); // undefined
console.log(res.num1); // 117
console.log(y); // 935
1、obj.child = obj = {num2: 935}
- 1)、从左到右声明变量: ```javascript // 1、声明 obj.child, 原 obj 对象变为如下 let obj = { num1: 117, child: undefined }
// 2、声明 obj
- 2)、 从右到左赋值
```javascript
// 1. 为 obj 赋值
let obj = {num2: 935}
// 2. 为 obj.child 赋值, 注意这里的 obj 指的是原 obj 的地址, 而不是上一行刚被赋值的新的 obj
let obj = {
num1: 117,
child: {num2: 935}
}
// 由于原 obj 的地址实际上是被 res 引用了,因此上面的代码可以理解为以下形式
let res = {
num1: 117,
child: obj
}
2、var y = res.child.num2
前面可以看出,res 其实就是 原 obj,且被赋予了新的属性 num2,因此可以正常输出