先从几道题目引入。
题目(答案在最后一节)
- typeof能判断哪些类型?
- 何时使用
===
?何时使用==
? - 值类型和引用类型的区别?
- 手写深拷贝(涉及递归)
知识点
-
变量类型
-
变量计算
变量类型相关知识点
- 值类型vs引用类型
- typeof运算符
- 深拷贝
1. 值类型vs引用类型
? 深入分析:
? 值类型都是在栈中存储的。
? 引用类型的值会存储在堆中。
? 图中代码把a
赋值为age=20
的一个对象,这样会在堆中申请一个地址,然后把age=20
放在堆中,把对应的key值存为这个内存地址,然后让变量a
指向这个内存地址。也就是说,此时变量a中存储的并不是{age: 20}
这个对象,而是一个内存地址,这个地址指向{age: 20}
这个对象。紧接着,把b
赋值为a
,其实就是把地址赋值给了b
。此时a
和b
指向了同一个内存地址,也就是指向了同一个对象。
-
常见值类型:undefined, string, number, boolean, symbol
// 常见值类型 let a; // undefined const str = "abc"; // string const n = 100; // number const b = true; // boolean const s = Symbol("s"); //symbol
-
常见引用类型:对象,数组,null(特殊引用类型,指针指向为空地址),函数(特殊引用类型,但不用于数据存储,没有复制、拷贝一说)
// 常见引用类型 const obj = { x: 100 }; const arr = ["a", "b", "c"]; const n = null; // 特殊引用类型,指针指向为空地址 function fn() {} // 特殊引用类型,但不用于存储数据,所以没有“拷贝”、“复制”一说
2. typeof运算符
typeof能用来做什么:
- 识别所有值类型
- 识别函数
- 判断是否是引用类型(不可再细分)
3. 手写深拷贝
先来看浅拷贝:
/**
* 浅拷贝
*/
const obj1 = {
age: 20,
name: "xxx",
address: {
city: "beijing",
},
skill: ["html", "css", "javascript"],
};
const obj2 = obj1;
obj2.address.city = "shanghai";
console.log(obj1);
以下是深拷贝:(?????要会默写)
/**
* 深拷贝
* @param {*} obj 要拷贝的对象
* @returns result 拷贝后的结果
*/
function deepClone(obj = {}) {
// 首先排除不是对象或者数组的情况
// obj是null,或不是对象或者数组,直接返回
if (typeof obj !== "object" || obj == null) return obj;
// 初始化返回结果
let result;
if (obj instanceof Array) {
result = [];
} else {
result = {};
}
for (let key in obj) {
// 保证key不是原型的属性
if (obj.hasOwnProperty(key)) {
// 递归调用
result[key] = deepClone(obj[key]);
}
}
return result;
}
变量计算相关知识点
- 类型转换
类型转换(这里有坑)
以下场景发生类型转换较多:
- 字符串拼接
- ==
- if语句和逻辑运算
知识点:
-
除了
==null
之外,其他一律都用===
-
truly变量和falsely变量
- truly变量:
!!a === true
的变量 - falsely变量:
!!a === false
的变量
- truly变量:
-
在if语句中判断的就是truly变量和falsely变量
// truly变量 const a = true; if (a) { console.log("a是truly变量"); } const b = 100; if (b) { console.log("b是truly变量"); }
// falsely变量 const c = ""; if (c) { console.log("这个if无法执行"); } const d = null; if (d) { console.log("这个if无法执行"); } let e; if (e) { console.log("这个if无法执行"); }
-
逻辑运算同理
console.log(10 && 0); // 0 console.log("" || "abc"); //‘abc‘ console.log(!window.abc); // true
第一节题目答案
-
typeof能判断哪些类型?
- 识别所有值类型
- 识别函数
- 判断是否是引用类型(不可再细分)
-
何时使用
===
?何时使用==
?==
会隐式地做类型转换,让两个值尝试相等。一般情况下,除了
==null
之外,其他一律都用===
-
值类型和引用类型的区别?
在内存中,值类型存在栈中,引用类型存在堆中。复制的时候,值类型直接复制,引用类型复制的是地址。
-
手写深拷贝(涉及递归)
- 注意点:
- 注意判断值类型和引用类型
- 注意判断是数组还是对象
- 递归
- 注意点:
/**
* 深拷贝
* @param {*} obj 要拷贝的对象
* @returns result 拷贝后的结果
*/
function deepClone(obj = {}) {
// 首先排除不是对象或者数组的情况
// obj是null,或不是对象或者数组,直接返回
if (typeof obj !== "object" || obj == null) return obj;
// 初始化返回结果
let result;
if (obj instanceof Array) {
result = [];
} else {
result = {};
}
for (let key in obj) {
// 保证key不是原型的属性
if (obj.hasOwnProperty(key)) {
// 递归调用
result[key] = deepClone(obj[key]);
}
}
return result;
}