好像自从使用框架之后,对jquery的依赖越来越低了,其好像已经慢慢作为一个工具库的存在了。新项目商量之下,为了减小文件大小,干脆直接不用jquer2,对于一些需要的工具函数直接从jquery提取到一个自己写的工具文件tool.js中。在提取的过程中,也慢慢理解了jquery一些工具函数的源码
深拷贝和浅拷贝的使用场景不同,并没有好坏之分,像对一些基本数据类型,直接可以使用浅拷贝对处理数据。但是对于基本引用类型如嵌套对象,数组(包含着对象的数组),那么就需要使用到深拷贝了。
不想看前面深浅拷贝对比的,可以直接拉到第二章看jquery源码实现
1.浅拷贝解析
原生js也有一些提供拷贝的函数,比如数组的Array.slice(0),Array.concat(),对象的Object.create(),Object.assign()等等,但是都是浅拷贝,遇到二维数组,嵌套对象就通通失败了(以前不懂的时候,真的被坑的不要不要的啊)。
比如下面这个例子,都是在只有基本数据类型的情况下,使用浅拷贝就可以了。
但是如果以上例子将基本数据类型换成引用类型Object和Array呢?
|
|
为什么会这样子,原因其实也不复杂。js内存分为栈内存和堆内存。所有的基本数据类型都是存储在栈内存中,而引用类型则是存储在堆内存中,提供了一个地址放在了栈内存中。当我们要获取引用类型的值时,先从栈内存获得地址,再根据地址去堆内存中获得值。因此也叫按引用访问。
(去网上浅拷贝了一张图片,因为拷贝了一个图片地址)
而我们上面例子中,每个数组和对象每个属性存储的引用类型obj其实是个地址,我们只是简单的拷贝了属性值,其实就是拷贝了一个地址。所以我们在新对象里进行修改时,由于是通过同一个地址修改了值。因为和原对象共用了一个地址,所以自然就修改了原对象的值了。
2.深拷贝解析
前面解析了浅拷贝。因为我们项目对大型数据处理占据了大头,其中不可避免的会经常用到深拷贝这块。那么深拷贝是怎么实现的。
其实也很简单,就是根据地址找到你堆内存中的值,不断递归深入拷贝下去,直到为基本数据类型为止,接下去就贴上深拷贝代码。
在讲jquey前,还有一个很暴力的方式JSON.parse()和JSON.stringify();缺点是
- 数据不能包含函数。
- 如果某个对象属性值为null,会形成一个对象的闭环12345678910111213141516171819202122232425let obj = {a: 1,b: 2,c: [1,2,3],d: function() {console.log("asdfghj");}};let result1 = JSON.stringify(target);console.log(result1); // 输出结果为"{"a":1,"b":2,"c":[1,2,3]}",函数直接没了const obj = {foo: {name: 'foo',bar: {name: 'bar'baz: {name: 'baz',aChild: null // 待会将指向obj.bar}}}}obj.foo.bar.baz.aChild = obj.foo // foo->bar->baz->aChild->foo形成环JSON.stringify(obj) // => TypeError: Converting circular personucture to JSON
好了,最后贴上jquery深拷贝的代码和自己一些理解的注释
在看上段代码中,又发现了几个好方法在业务中会用到的,可以让代码更严谨
以上基本就是jquery.extend代码的解析了。extend是jquery中一个极其重要的方法,jquery本身就用它扩展了许多静态方法和实例方法