var let const 有什么区别
1、首先是他们的作用域不同:var 的作用域是 **函数作用域 **或者说是全局作用域;而 let 和 const 是块级作用域,解决了 var 在 if 或 for 语句中造成内存泄漏的问题 让代码更健壮
2、其次就是他们的 **声明提升 **行为:var 有声明提升行为,他会把变量的声明提升到作用域顶部并且初始化为undefined,这意味着在声明前访问不会报错;而 let 和 const 不会提升,从作用域到变量声明之前存在暂时性死区(TDZ),在声明前访问会抛出报错 ReferenceError 这是一种更安全更符合预期的行为
3、最后从 **声明和赋值规则 **来看:var 既可以重新赋值,还可以重复声明;let 不能再同一作用于下重复声明,但他可以重新赋值;const 最严格,既不能重新赋值也不能重新声明 不过有个值得注意的点:const声明的引用类型仍可以修改对象内部的属性值,只是不能修改其变量的引用
数据类型和 typeof 的陷阱
八大数据类型:string number boolen null undefined symbol bigint 对象类型
**typeof null**为什么输出 object:这是一个历史遗留bug,在早期的js实现中,null 表示的是一个 NULL 空指针(0x00),对象的类型标签恰好也是0,这就导致 typeof 将 null 误判为对象
无法区分具体对象类型:
- 使用
===来判断 null - 使用
Array.isArray(arr)来判断 Array Object.prototype.toString.call(obj)通用方法
深拷贝和浅拷贝
浅拷贝只复制第一层数据,如果属性是值类型则复制值,如果属性是引用类型则复制** 内存地址,**内层对象仍共享引用。常用展开运算符...实现
而深拷贝会递归的完全复制所有层级数据,所有引用类型属性都会被重新创建,新旧对象完全独立,互不影响。
深拷贝实现方法:
- 简单的可以用
JSON.parse(JSON.stringify(obj))实现,但他会忽略 undefined、symbol、function属性,并且 Date 对象会变成字符串,无法处理循环引用(会报错) - 更好的可以用
structuredClone(obj),但他依然无法拷贝函数和 error 对象 - 最好的可以用第三方库
lodash.cloneDeep(obj)
// 手写实现functiondeepClone(obj,hash=newWeakMap()){if(obj===null||typeofobj!=='object')returnobj;if(objinstanceofDate)returnnewDate(obj);if(objinstanceofRegExp)returnnewRegExp(obj);if(hash.has(obj))returnhash.get(obj);constclone=Array.isArray(obj)?[]:{};hash.set(obj,clone);for(letkeyinobj){if(obj.hasOwnProperty(key)){clone[key]=deepClone(obj[key],hash);}}returnclone;}=== 和 == 的区别
=== 遵循严格相等的规则,只有当类型和值都想同时才返回 true,且不会进行类型转换
== 遵循宽松相等的规则,类型不同时会先转换类型,在比较值,但转换规则复杂易出错
最佳实践:
- 几乎永远使用===
- 唯一例外:用
xxx == NULL一次性检测xxx是否是 null 或 undefined - 特殊情况:NaN 不等于任何值,包括他自己,只能用 Number.isNaN()
隐式类型转换有哪些坑
规则:
- 假值合集:false,0,+0,-0,0n,“”,null,undefined,NaN(其他的包括[]、{}都为ture)
- 当一个对象类型需要被转换为原始类型时,引擎会先检查这个对象自身和他的原型链上有没有
**Symbol.toPrimitive**的方法,如果没有则会根据期望的转换类型,调用** valueOf()** 和toString()方法(期望转换成 String 时先调用 toString 再调用 valueOf,期望转换成 Number 时则相反)
坑点:
- +运算符的歧义:任一操作数为字符串时进行字符串拼接,否则进行数字加法
- ==非严格相等:1、
**null == undefined**定义返回 true
2、字符串和数字进行比较时,自动将String 转为 Number
3、当布尔值和任意类型比较时,自动将boolen 转为 number
4、对象和原始数据类型进行比较时,自动将对象按规则转换为原始类型
// 经典面试题console.log([]==![])// true// 过程:// ![] => !(true) => false// [] == false => [] == 0 => "" == 0 => 0 == 0