内容:

  1. jQuery无new构建实例
  2. 共享原型设计
  3. extend源码解析

image.png
2.1 jQuery 整体架构分析 以及 extend方法 - 图2
jQuery的Extend用法:

  1. var obj1 = {
  2. name: 'Max',
  3. list: {
  4. age: 21
  5. }
  6. };
  7. var obj2 = {
  8. items: {
  9. nan: 'Ch'
  10. },
  11. list: {
  12. gender: 'Male'
  13. }
  14. };
  15. // 给任意对象扩展属性
  16. var obj3 = $.extend(true, obj1, obj2);
  17. console.log(obj3);
  18. // 给jQuery本身扩展属性
  19. jQuery.extend({
  20. work: function() {
  21. }
  22. });
  23. jQuery.work();
  24. // 给jQuery对象实例扩展属性
  25. jQuery.fn.extend({
  26. gender: 'Male'
  27. });
  28. jQuery('').gender;


Code实现:

  1. (function(root) {
  2. var jQuery = function() {
  3. return new jQuery.prototype.init(); // 创建jQuery的实例对象,不能写 new jQuery(),会造成循环调用
  4. }
  5. // jQuery原型上扩展属性
  6. jQuery.fn = jQuery.prototype = {
  7. init: function() {
  8. },
  9. css: function() {
  10. }
  11. };
  12. // jQuery本身扩展和原型上扩展都调用了同一个方法 extend
  13. jQuery.fn.extend = jQuery.extend = function(){
  14. var target = arguments[0] || {};
  15. var length = arguments.length;
  16. var i = 1;
  17. var deep = false;
  18. var name, option, copy, src,isCopyArray, clone;
  19. // 第一个参数是否为布尔类型:target要为第二个参数,i要从第三个参数开始循环
  20. if(typeof target === "boolean") {
  21. deep = target;
  22. target = arguments[1];
  23. i = 2;
  24. }
  25. // 第一个参数必须是object
  26. if(typeof target !== 'object') {
  27. target = {};
  28. }
  29. if(i === length) {
  30. target = this;
  31. i--;
  32. }
  33. // 浅拷贝, 深拷贝
  34. //1.扩展:target = this; i = 0;length=1;
  35. //2.浅拷贝:target = arguments[0];i=1;
  36. //3.深拷贝:target = arguments[1];i=2;
  37. for(; i < length; i++) {
  38. if((option = arguments[i]) !== null) {
  39. for(name in option) {
  40. copy = option[name];
  41. src = target[name];
  42. if (deep && (jQuery.isPlainObject(copy) || (isCopyArray = jQuery.isArray(copy)))) {
  43. if(isCopyArray) {
  44. isCopyArray = false;
  45. clone = src && jQuery.isArray(src) ? src : [];
  46. }
  47. else {
  48. clone = src && jQuery.isPlainObject(src) ? src : {};
  49. }
  50. target[name] = jQuery.extend(deep, clone, copy);
  51. }
  52. else {
  53. target[name] = option[name];
  54. }
  55. }
  56. }
  57. }
  58. return target;
  59. }
  60. // 共享原型设计:init的原型等于jQuery的原型,这样new init()创建出来对象的原型也就是jQuery的原型
  61. jQuery.fn.init.prototype = jQuery.fn;
  62. jQuery.extend({
  63. isPlainObject: function(obj) {
  64. return toString.call(obj) === "[object Object]";
  65. },
  66. isArray: function(obj) {
  67. return toString.call(obj) === "[object Array]";
  68. }
  69. });
  70. root.$ = root.jQuery = jQuery; // $是jQuery的一个别名
  71. })(this);

思考问题:
1. jQuery实际是new jQuery.fn.init()实例化对象,那么常用的方法如$.ajax,$.get是怎么实现的?
A: ajax,get等都是jQuery的静态方法;通过 jQuery.extend({ajax:…, get: ….}) 去实现;

  1. $.extend()与$.fn.extend()的区别?
    $.extend() 是向 jQuery上扩展属性,$.fn.extend() 是向jQuery的实例对象上扩展属性;可以参考下面的Code。
    通过$.extend()扩展的属性,要通过jQuery.属性名来访问;
    通过$.fn.extend()扩展的属性,要通过jQuery(‘selector’).属性名来访问(也就是通过jQuery的实例对象访问)。

    1. // 给jQuery本身扩展属性
    2. jQuery.extend({
    3. work: function() {
    4. }
    5. });
    6. jQuery.work();
    7. // 给jQuery对象实例扩展属性
    8. jQuery.fn.extend({
    9. gender: 'Male'
    10. });
    11. jQuery('').gender;

具体例子可以参考:
https://www.yuque.com/niruoanhao/cc61zh/qgw5re

需要注意一下的情况:

1. JSON.stringify和JSON.parse() (深拷贝)

  1. var x = {
  2. a: 1,
  3. b: undefined,
  4. c: null,
  5. d: function() {},
  6. e: Symbol,
  7. f: new Date,
  8. }
  9. var y = JSON.parse(JSON.stringify(x));
  10. console.log(y) /*{
  11. a: 1
  12. c: null
  13. f: "2019-08-30T07:11:45.286Z"
  14. }*/

这种拷贝方法会造成值为undefined、Symbol、function的属性丢失,如果确定要拷贝的对象没有这几类值的话就放心大胆的使用吧。

2. 扩展符…

  1. var x = {
  2. a: 1,
  3. b: {
  4. c: 1
  5. }
  6. }
  7. var y = {...x};
  8. y.a = 13;
  9. y.b.c = 15;
  10. console.log(x) // x:{a:1,b:{c:15}}

这个结果是不是似曾相识,这和我们前面写的浅拷贝一模一样哦,所以 … 可以用来拷一层结构的数据,多层的话就得谨慎使用了。

3. object.assign

  1. var m1 = {a:1,b:{x:1,y:2}};
  2. var n1 = {b:{x1:3,y1:4}};
  3. var obj1 = Object.assign(m1,n1) //obj1:{a:1,b:{x1:3,y1:4}}

浅拷贝。

思维扩展

我们使用拷贝的目的是复制一份,原来的对象保持不变,之前一直围绕如何让复制出来对象与原对象取消关联,是否可以换个思路,如冻结原对象。

freeze

  1. var x = {a: 1,b:{c:1}}
  2. var y = x;
  3. Object.freeze(x);
  4. y.a = 2;
  5. console.log(x, y) // x:{a:1} y:{a:1}

第一个尝试案例就失败了,x,y指向同一个指针,而这个指针索引的对象被冻结,导致y的修改是无效的。经过尝试freeze只能冻结第一层结构,如x.b.c是没有冻结的,可以改变,如果想深度冻结一个对象,可以和深拷贝一样使用递归冻结。