jQuery源码阅读(八)---jQuery中的继承extend
来源:互联网 发布:js 创建key value数组 编辑:程序博客网 时间:2024/05/17 22:20
今天看了jQuery源码中关于extend函数的部分,这部分就相当于jQuery继承,后面在整理的过程中说明如何继承。
还是跟之前的分析方法一样,要分析一个函数的实现,首先得知道函数是干什么的,它的功能是啥。
extend方法应用
扩展插件
在jQuery的学习当中,我们学过如何去写一个插件,而且插件分全局插件和实例插件,即一种是直接挂载在jQuery上的,另一种是挂载在jQuery实例对象上的。
比如下面两种实现:
扩展全局插件:
$.extend({ add: function(a, b){ return a + b; }});
$.add(4,9); //返回13
对象插件:
$.fn.extend({ add : function(a, b){ return a + b; }})
$().add(2,8) //返回10
扩展对象
这也可以算是jQuery中实现继承的一种方式。
a = { name : 'liu'}b = { name: 'yang'}var res = $.extend(a, b) //res可以说是继承了a和b的属性和方法////默认浅拷贝,改变a.name不会影响b.nameaa = { name: { age: 20 }}bb = { name: { age: 15 }}$.extend(aa, bb)//浅拷贝,只拷贝对象,不会把内部具体的属性也拷贝//所以修改a.name.age会改变b.name.ageaa.name.age = 30;//此时bb.name.age也是30//如果改用深拷贝的话$.extend(true, aa, bb)//aa和bb中的name是不同的对象,指向不同的内存区域//因此改变aa.name.age不会影响bb.name.age
extend方法在扩展对象时,最前面可以传一个布尔值的参数true,表示扩展对象时使用深拷贝,即将所有层级的对象属性都进行拷贝。而不加布尔值的参数,则默认是浅拷贝,即不会复制内层级的属性和方法。
extend源码分析
jQuery.extend = jQuery.fn.extend = function() {};
首先,我想说的是 jQuery.extend和jQuery.fn.extend是同一份代码,也就是说 实现思路是一样的.那如何才能确定是在jQuery上扩展的,还是在jQuery实例对象上扩展的?
JS中有个this的概念,即指向当前的上下文。具体点来说.
//直接调用函数时function a(){ return this;}a(); //返回的是window对象
//如果通过对象调函数var obj = { b: function(){ return this; }}obj.b(); //返回的是Object对象
所以如果$.extend(),this指向的是jQuery;
,如果$.fn.extend()
,this
指向jQuery.fn
也就是jQuery.prototype
,那么在原型上扩展一个方法,就相当于在jQuery实例中可以调用该方法,从而实现扩展的目的。
接着下面的源码:
var options, name, src, copy, copyIsArray, clone, //从这块可以学习到,如果不确定函数中有多少个参数时,可以用arguments来访问。 target = arguments[0] || {}, //如果是深拷贝,target此时为true; //如果不是,target此时是要扩展的第一个参数; i = 1, length = arguments.length, deep = false; // 深拷贝的情况 if ( typeof target === "boolean" ) { deep = target; target = arguments[1] || {}; // 跳过true和要扩展的第一个参数 i = 2; } //如果不是对象,不是函数,target设为空对象,以便和后面对象能够合并 if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } //如果只有一个参数,那么就认为这是扩展插件,所以target就是this对象。前面也讲了什么情况下,this是jQuery,什么情况下this是jQuery.fn if ( length === i ) { target = this; --i; //这个时候就从第一个参数开始处理 } for ( ; i < length; i++ ) { //如果是对象扩展并且是浅拷贝,那么i从1开始 //如果是对象扩展并且是深拷贝,那么i从2开始 //如果是插件扩展,那么i从0开始 //前面已经处理好了 if ( (options = arguments[ i ]) != null ) { for ( name in options ) { src = target[ name ]; copy = options[ name ]; //注意这部分,下面会讲到 if ( target === copy ) { continue; } //如果是深拷贝,那么对象内层的每一级属性都要拷贝,所以是一个递归的过程 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { if ( copyIsArray ) { copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; } else { clone = src && jQuery.isPlainObject(src) ? src : {}; } // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); } else if ( copy !== undefined ) { //如果不是深拷贝,就直接将name属性加到target对象里面了 target[ name ] = copy; } } } } //最后返回扩展后的target对象;或者返回jQuery或者返回jQuery.fn return target;
下来缕一缕上面提到的
if ( target === copy ) { continue;}
比如这么一种情况:
var obj = { age : 20}var obj1 = { age: obj}var res = $.extend(obj, obj1);
这种情况下,在extend函数内部,target为 obj = { age : 20 }, copy = options[‘age’] = obj = { age : 20 }
所以判断target和copy相等,就会continue,跳过该次循环,那为什么要这样做呢?
我们先把if ( target === copy ) { continue; }
注释掉,看结果是什么?
可以看到,返回的是一个含有一个name属性的对象,而name属性又指向该对象,这样无限循环下去了。为什么会出现这种情况呢?
因为如果去掉continue的话,会继续后面的执行,即
target[ name ] = copy;
在这句执行之前,target指向一个Object对象,copy也是指向该对象,那么对target的修改也会影响copy对象,所以target.name修改为copy,相当于copy.name也修改为copy,这样就形成了无限循环的对象,这样实际上没有什么意义,所以jQuery避免了这种情况。可见,jQuery各方面的考虑是非常全面。希望能学到更多,理解更深刻!
- jQuery源码阅读(八)---jQuery中的继承extend
- jquery源码阅读之jquery.extend
- 浅谈jQuery源码(八)——$.extend
- jquery源码-jquery.extend()
- jQuery源码-jQuery.extend
- jQuery源码研究分析学习笔记-jQuery.extend()、jQuery.fn.extend()(八)
- jQuery 源码学习(一)jQuery.extend()
- jQuery继承extend用法
- jQuery-源码阅读,JavaScript原生继承方式与jQuery中的继承
- jquery.extend源码分析
- jQuery.extend()源码解析
- jQuery-源码阅读,extend()与工具方法、实例方法
- jQuery中的extend方法
- jQuery中的extend方法
- jquery中的extend
- jQuery中的extend函数
- 菜鸡看jquery源码(3)extend
- Jquery中的Jquery.extend, Jquery.fn.extend,Jquery.prototype
- TextRank: Bringing Order into Texts阅读笔记
- 默认成员函数+运算符重载
- Button 已经被点击
- 测试
- Arrays.asList解析
- jQuery源码阅读(八)---jQuery中的继承extend
- Android蓝牙4.0之玩爆智能穿戴、家具(二)【进阶篇】
- org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection;
- Ehcache配置参数详解
- 面向对象复习一
- TCP协议中的三次握手和四次挥手(图解)
- 常用设计模式之简单工厂模式
- 如何js正则表达式判断ip地址的合法性?
- 编程练习二维数组 java