Hi,这里是正在参加青训营🪖的JustHappy,入坑前端也有一年了,感谢青训营给我这个机会让我回到原点,也是感慨万千啊,So!来看看我这个三流前端目前对基础三件套的理解吧!!!这篇主要浅浅聊聊JS变量相关的问题,更深入的JS语法细节过一阵在我会再写一篇总结,so!让我们开始吧
变量声明 && 变量类型
var、let、const
let和const是ES6(ECMAScript 2015)引入的,旨在提供更好的作用域控制和变量声明的安全性。在现代JavaScript开发中,推荐使用let和const来代替var,以编写更清晰、更易于维护的代码。
为什么大家都不继续使用var?
var声明的变量会被提升到它们所在的作用域的顶部(这怎么形容呢?就相当于在你代码的第一行前面声明了变量),但是它们的赋值不会提升
这是啥意思呢?我们来看看下面这几小段代码,大家也可以在自己的设备上跑一下
- 我们尝试单独输出一个未被声明的变量
console.log(myVal)
-
显而易见,这行代码是会报错的
-
但是如果我们在这行代码的下面使用var去声明这个变量,再在下面输出就会有以下情况
console.log(myVar); // 输出:undefined,而不是报错,因为变量声明被提升,但赋值没有提升
var myVar = 5;
console.log(myVar); // 输出:5
-
我们都知道代码是顺序执行的,按道理说第一个
console.log(myVal)应该会报错,但是却输出了undefined,这说明了该变量在这一行处于一个“被声明但是为被赋值的状态”,而以上现象就是因为var变量的声明被提升、但赋值并没有被提升 -
这会导致什么问题呢?
- 这可能导致在变量赋值之前就引用了未声明的变量,导致程序出现错误。
let和const
我们在使用let和const的时候是不存在变量提升这一问题,这是因为let和const声明变量会经历所谓的“暂时性死区”(Temporal Dead Zone,TDZ)
- 下面两段代码也证明了这一点
console.log(letVal); // 抛出 ReferenceError: bar is not defined
let letVal = 'aaa';
console.log(constVal); // 抛出 ReferenceError: qux is not defined
const constVal = 'bbb';
你真的了解变量类型吗?
值类型 or 引用类型(即简单类型 和 复杂类型)
值类型 又或者说是 简单类型 吧,在JavaScript中有
我们先来看以下两段代码
// 值类型特征演示
let a = 10;
let b = a;
b = 20;
console.log(a); // 10
// 引用类型特征演示
let c = { name: "Jack" };
let d = c;
d.name = "Tom";
console.log(c.name); // Tom
很直观的可以看到值类型演示中原来的值没有被改变,但是在引用类型中却被改变了
所以这是为什么呢?
不只是JavaScript,几乎是所有的编程语言都有这个特性,这和数据在内存中的存储有关
在JavaScript中,值类型和引用类型在内存中的存储方式有显著的区别,这主要体现在它们存储的位置和访问方式上:
值类型(简单类型)
- 存储位置:值类型的数据直接存储在栈(stack)内存中。
- 存储方式:当值类型的数据被创建时,它们会直接被复制到栈中。例如,当你声明一个变量并赋予一个值时,这个值就会被存储在栈中。
引用类型(复杂类型)
- 存储位置:引用类型的数据存储在堆(heap)内存中。
- 存储方式:引用类型的变量实际上存储的是指向堆中数据的指针(引用)。当引用类型的数据被创建时,它们会被存储在堆中,而变量则保存了指向这些数据的引用。
那么对于一引用数据类型(复杂类型),我们用一个新的变量拷贝完再修改的话,如何使得原本的数据不被修改呢。于是乎我们来聊聊深拷贝和浅拷贝
深拷贝和浅拷贝
由上我们知道,只有引用类型(复杂数据类型)需要进行深拷贝,所以在此之前我们需要掌握如何判断一个数据是否是引用类型,所以我们来看看typeof()
有关typeof()
typeof()可以直接返回简单数据类型的确切类型,而对复杂数据类型来说,则返回object,对于函数则返回function,以下是返回结果示例
// 对于简单数据类型
console.log(typeof 10); // number
console.log(typeof "Jack"); // string
console.log(typeof true); // boolean
console.log(typeof Symbol()); // symbol
console.log(typeof undefined); // undefined
//对于复杂数据类型
console.log(typeof {}); // object
console.log(typeof []); // object
//对于函数
console.log(typeof function () {}); // function
但是typeof()有个历史遗留问题,当判断null的时候也会返回object
console.log(typeof null); // object
我们来实现一个深拷贝吧!!!
实现深拷贝有多种方式,我们这里就写一种最重要的,最能体现编程思想的递归深拷贝吧
const deepClone = (obj) => {
if (typeof obj !== "object" || obj === null) return obj;
// 初始化反回结果
let result;
// 判断是数组还是对象
if (Array.isArray(obj)) {
result = [];
} else {
result = {};
}
for (let key in obj) {
// 保证key不是原型链上的属性
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key]);
}
}
return result;
};
以下是测试这段代码的示例
let e = {
name: "Jack",
sex: "male",
address: {
city: "Beijing",
},
age: 18,
};
let f = deepClone(e);
f.address.city = "Shanghai";
console.log(e); // { name: 'Jack', sex: 'male', address: { city: 'Beijing' }, age: 18 }
console.log(f); // { name: 'Jack', sex: 'male', address: { city: 'Shanghai' }, age: 18 }