JavaScript面试八股文(更新中)
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)来判断 ArrayObject.prototype.toString.call(obj)通用方法深拷贝和浅拷贝浅拷贝只复制第一层数据如果属性是值类型则复制值如果属性是引用类型则复制** 内存地址**内层对象仍共享引用。常用展开运算符...实现而深拷贝会递归的完全复制所有层级数据所有引用类型属性都会被重新创建新旧对象完全独立互不影响。深拷贝实现方法简单的可以用JSON.parse(JSON.stringify(obj))实现但他会忽略 undefined、symbol、function属性并且 Date 对象会变成字符串无法处理循环引用会报错更好的可以用structuredClone(obj)但他依然无法拷贝函数和 error 对象最好的可以用第三方库lodash.cloneDeep(obj)// 手写实现functiondeepClone(obj,hashnewWeakMap()){if(objnull||typeofobj!object)returnobj;if(objinstanceofDate)returnnewDate(obj);if(objinstanceofRegExp)returnnewRegExp(obj);if(hash.has(obj))returnhash.get(obj);constcloneArray.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()隐式类型转换有哪些坑规则假值合集false00-00n“”nullundefinedNaN其他的包括[]、{}都为ture当一个对象类型需要被转换为原始类型时引擎会先检查这个对象自身和他的原型链上有没有**Symbol.toPrimitive**的方法如果没有则会根据期望的转换类型调用** valueOf()** 和toString()方法期望转换成 String 时先调用 toString 再调用 valueOf期望转换成 Number 时则相反坑点运算符的歧义任一操作数为字符串时进行字符串拼接否则进行数字加法非严格相等1、**null undefined**定义返回 true2、字符串和数字进行比较时自动将String 转为 Number3、当布尔值和任意类型比较时自动将boolen 转为 number4、对象和原始数据类型进行比较时自动将对象按规则转换为原始类型// 经典面试题console.log([]![])// true// 过程// ![] !(true) false// [] false [] 0 0 0 0