jquery源码分析
jquery$(selector).bar()调用方法的实现
$(selector)需要返回一个利用selector初始化的实例,并且这个实例能够访问jquery的原型方法,并且不使用new操作符。
实现这两步,需要:
- 构造函数$需要返回一个用new操作符调用的构造函数init的实例
- 将构造函数init的prototype属性设置为jQuery的prototype属性
我们可以这样做:
var $ = function(selector,context){
*return new init();
}
$.prototype = {
foo:function();
bar:xxx;
}
function init(){
...;
}
*init.prototype = $.prototype
var something = $(selector);
但是在jquery中,init函数是在$.prototype内部的,因此带星号的语句需要修改为:
return new $.prototype.init();
$.prototype.init.prototype = $.prototype;
jquery的源码则是
return new jQuery.fn.init( selector, context, rootjQuery );//fn为jquery.prototype的一个引用。
jquery链式调用
在所有的方法最后添加return this即可实现链式调用。
jquery extent函数
extent函数源码分析
jQuery.extend = jQuery.fn.extend = function() {
var src, copyIsArray, copy, name, options, clone,
target = arguments[0] || {}, // 常见用法 jQuery.extend( obj1, obj2 ),此时,target为arguments[0]
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) { // 如果第一个参数为true,即 jQuery.extend( true, obj1, obj2 ); 的情况
deep = target; // 此时target是true
target = arguments[1] || {}; // target改为 obj1
// skip the boolean and the target
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) { // 处理奇怪的情况,比如 jQuery.extend( 'hello' , {nick: 'casper})~~
target = {};
}
// extend jQuery itself if only one argument is passed
if ( length === i ) { // 处理这种情况 jQuery.extend(obj),或 jQuery.fn.extend( obj )
target = this; // jQuery.extend时,this指的是jQuery;jQuery.fn.extend时,this指的是jQuery.fn
--i;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) { // 比如 jQuery.extend( obj1, obj2, obj3, ojb4 ),options则为 obj2、obj3...
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) { // 防止自引用,不赘述
continue;
}
// Recurse if we're merging plain objects or arrays
// 如果是深拷贝,且被拷贝的属性值本身是个对象
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) { // 被拷贝的属性值是个数组
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else { 被拷贝的属性值是个plainObject,比如{ nick: 'casper' }
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy ); // 递归~
// Don't bring in undefined values
} else if ( copy !== undefined ) { // 浅拷贝,且属性值不为undefined
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
}
extent函数源码分析引用自:http://www.cnblogs.com/aaronjs/p/3278578.html
实现自己的简单深复制函数
深复制需要遵守的规则:(假设将obj2中的属性深复制至obj1中)
- obj2中的某个属性bar为对象或者数组。如果obj1.bar为也为数组或对象,将obj1.bar与obj2.bar作为参数再次执行深复制;如果obj1.bar不为数组、对象或者obj.bar不存在,则新建一个数组、对象,与obj2.bar作为参数再次执行深复制。
- obj2中的某个属性foo不为数组或者对象,直接令obj1.foo = obj2.foo。
实现:(https://github.com/kangkang1234/deepCopy/blob/master/deepCopy.js
function deepCopy(){
var len = arguments.length;
if(len===1){
return arguments[0];
}else if(len===0){
return undefined;
}
var j=0;
for(;j<len;j++){
if(!(arguments[j] instanceof Array)&&!(arguments[j] instanceof Object)){
throw new TypeError("arguments must be object or array.");
}
}
var src,copy,option,copyIsArr;
var target = arguments[0] || {};
var i = 1;
for(;i<len;i++){
option = arguments[i];
for(name in option){
src = target[name];
copy = option[name];
if(copy&&((copyIsArr=copy instanceof Array)||(copy instanceof Object))){ //如果copy存在并且是数组或者对象
if(copyIsArr){ //如果copy是数组
src = (src&&src instanceof Array)?src:[]; //判断target中是否有相同属性名的属性,并且该属性为数组。
target[name] = deepCopy(src,copy);
}else{
src = src?src:{};
target[name] = deepCopy(src,copy);
}
}
else {
target[name] = copy;
}
}
}
return target;
}