读懂源码系列3lodash-是如何实现深拷贝的上

前言上一篇文章 「前端面试题系列9」浅拷贝与深拷贝的含义、区别及实现 中提到了深拷贝的实现方法,从递归调用,到 JSON,再到终极方案 cloneForce。 不经让我想到,lodash 中的 _.cloneDeep 方法。它是如何实现深拷贝的呢?今天,就让我们来具体地解读一下 _.cloneDeep 的源码实现。 源码中的内容比较多,为了能将知识点讲明白,也为了更好的阅读体验,将会分为上下 2 篇进行解读。今天主要会涉及位掩码、对象判断、数组和正则的深拷贝写法。 ok,现在就让我们深入源码,共同探索吧~ _.cloneDeep 的源码实现它的源码内容很少,因为主要还是靠 baseClone 去实现。 /** Used to compose bitmasks for cloning. */const CLONE_DEEP_FLAG = 1const CLONE_SYMBOLS_FLAG = 4function cloneDeep(value) { return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG)}刚看到前两行的常量就懵了,它们的用意是什么?然后,传入 baseClone 的第二个参数,似乎还将那两个常量做了运算,其结果是什么?这么做的目的是什么? 一番查找之后,终于明白这里其实涉及到了 位掩码 与 位运算 的概念。下面就来详细讲解一下。 位掩码技术回到第一行注释:Used to compose bitmasks for cloning。意思是,用于构成克隆方法的位掩码。 从注释看,这里的 CLONE_DEEP_FLAG 和 CLONE_SYMBOLS_FLAG 就是位掩码了,而 CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG 其实是 位运算 中的 按位或 方法。 ...

May 8, 2019 · 4 min · jiezi

让前端面试不在难(三)

今天聊一下clone这个前端面试高频问题,由此引出typeof、instanceof、Object.prototype.toString这些javascript Api。下面我们先详细的聊一下,完了解决下面试官的问题。typeoftypeof能获取一个变量或表达式的类型。原始类型BooleanNullUndefinedStringSymbolNumberSymbol和 引用类型 Object,Function下面看一些栗子 //基础类型也可以说非引用类型 let str = ‘hello word!’ console.log(typeof str) //string let num = 12 console.log(typeof num) //number let udf = undefined console.log(typeof udf) //undefined let bl = true console.log(typeof bl) //boolean let nl = null console.log(nl) //null let sl = Symbol() console.log(typeof sl) //symbol //复合类型也可以说是引用类型, let obj = { a: 1 } console.log(typeof obj) //object let arr = [1, 2, 3] console.log(typeof arr) //object //函数也属于引用类型,不过typeof却能准确的返回类型 function fn() {} console.log(typeof fn) //function从以上的执行结果可以看出,typeof不能够准确分返回所有类型instenceof我们从instenceof的实现来了解下instenceof是干什么的 // 模拟instenceof实现 // 1、instenceof接收两个参数 // 2、返回true或false function myInstenceof(X, Y) { let L = X.proto let R = Y.prototype if (L !== R) { return false } return true } // test function Fn() { } let newFn = new Fn() console.log(newFn) console.log(new Fn()) console.log(myInstenceof(newFn, new Fn())) //true console.log(myInstenceof([], new Array())) //true console.log(myInstenceof([], new Object())) //true以上demo我们就能看出,instenceof也不够靠谱,模拟实现就是判断X的原型知否在Y的原型链上。数组之所以instenceof Object为true是因为 [].prototype->new Array->new Object->null上边说了typeof和instenceof其实就是想说这两个对于深度clone的实现来说不够严谨要不就是多层判断。Object.prototype.toString.call()接下里我们说个靠谱的 Object.prototype.toString.call(’’); // [object String] Object.prototype.toString.call(1); // [object Number] Object.prototype.toString.call(true); // [object Boolean] Object.prototype.toString.call(undefined); // [object Undefined] Object.prototype.toString.call(null); // [object Null] Object.prototype.toString.call(new Function()); // [object Function] Object.prototype.toString.call(new Date()); // [object Date] Object.prototype.toString.call([]); // [object Array] Object.prototype.toString.call(new RegExp()); // [object RegExp] Object.prototype.toString.call(new Error()); // [object Error] Object.prototype.toString.call(document); // [object HTMLDocument] Object.prototype.toString.call(window); //[object Window]靠谱!接下来我们就用Object.prototype.toString.call()来解答一下面试题 function clone(obj, o) { //Object.prototype.toString.call(obj)返回类似[Object Array] 利用slice来截取我们需要的字符串 let type = Object.prototype.toString.call(obj).slice(8, -1) // 如果是Object if (type === ‘Object’) { o = {} for (let k in obj) { o[k] = clone(obj[k]); } // 如果是对象 } else if (type === ‘Array’) { o = [] for (let i = 0; i < obj.length; i++) { o.push(clone(obj[i])); } } else { // 非引用类型 o = obj } return o } let obj1 = { a: [1, 2, 3, 4, 5, 6], b: { c: 2 }, d: 1, f: function() { return 1 } } let obj2 = clone(obj1) obj2.f = function() { return 2 } obj2.a = 1 console.log(obj1) console.log(obj2)测试打印结果,obj2的改变不会影响到obj1。欢迎吐槽! ...

January 29, 2019 · 2 min · jiezi