JavaScript
一些问题。
0.1+0.2!==0.3
浏览器对于 64 位双精度浮点数的处理,1 位符号位,11 位指数位,52 位尾数。表现为二进制时超出 53 位后被 舍弃。
对于 2 的倍数不存在精度问题,1/2,1/4 这种。
相等判断
Object.is() 与比较操作符 “===”、“==”
== 进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。
=== 进行相等判断时,类型不一致时,不会做强制类型准换,直接返回 false。
使用 Object.is 来进行相等判断时,一般情况下和 === 的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 是相等的。
深拷贝浅拷贝
-
浅拷贝只复制对象的第一层。第一层的值如果是对象,拷贝的是对象的引用。
浅拷贝:扩展运算符,
Object.assign({}, obj)。Object.assign(targetObj, obj1,[obj2])将源对象的所有可枚举属性复制到目标对象。返回的是目标对象本身。可以有多个源对象。let outObj = {
inObj: { a: 1, b: 2 },
};
let newObj = { ...outObj };
newObj.inObj.a = 2;
console.log(outObj); // {inObj: {a: 2, b: 2}}
let outObj = {
inObj: { a: 1, b: 2 },
};
let newObj = Object.assign({}, outObj);
newObj.inObj.a = 2;
console.log(outObj); // {inObj: {a: 2, b: 2}} -
深拷贝复制对象的所有层级。
JSON.parse(JSON.stringify(data))是深拷贝。但不能拷贝function,不能拷贝循环引用的对象等。
手写深拷贝
对象/原始数据类型:递归复制一份。
带环引用:用 map 建立映射做缓存,防止循环引用。
正则类/Date 类单独处理。
手写代码
//如果带环,需要缓存,确认当前对象是否复制过,如果复制过,就直接指向它。用map防止循环引用
function cloneDeep(obj) {
let cache = new Map(); //由原对象映射到其复制品
function clone(obj) {
if (cache.has(obj)) {
return cache.get(obj);
}
let res;
if (obj && typeof obj === 'object') {
//引用数据类型,且不是null
if (Array.isArray(obj)) {
//数组
res = [];
} else {
res = {};
}
cache.set(obj, res);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
res[key] = clone(obj[key]);
}
}
return res;
} else {
return obj;
}
}
return clone(obj);
}
纯函数
一个函数的返回结果只依赖它的参数,并在执行过程中没有任何的副作用,被称为纯函数。
为什么用纯函数
纯函数非常靠谱,稳定,不会产生不可预料的行为,不会对外部产生影响。
for in 与 for of
- for in 主要用于遍历对象所有可枚举属性,且会遍历对象原型链上的属性,性能较低。也可遍历数组,但是遍历出来的是数组的索引。
- for of 用于遍历所有有 iterator 接口的数据结构。可以遍历数组,类数组对象、Map,Set,字符串等,不会遍历原型链。普通的对象使用 for of 会报错,如果需要可以自己定义相应的 Iterator 接口,默认的 Iterator 接口部署在数据结构的
Symbol.iterator属性。