1.jQuery.fn给我们提供了扩展开发的接口,原因就是在定义处使用原型链的方式,所以修改jQuery.fn实际上就是对jQuery.prototype的修改。
jQuery.fn源码如下:
jQuery.fn =jQuery.prototype = {
jquery: version,
constructor: jQuery,
……
// Execute a callbackfor every element in the matched set.
each: function(callback ) {
//为了测试在这里加了个特殊情况
if(callback() == 123) return jQuery.each(this,callback,123)
returnjQuery.each( this, callback );
},
……
}
2.为了避免和其他JavaScript库冲突,最好将jQuery传递给一个自我执行的封闭程序,jQuery在此程序中映射为$符号,这样可以避免$号被其他库覆写。同时,一个插件的意图仅仅是以某种方式修改收集的元素,并把它们传递给链中的下一个方法。这是jQuery的设计之美,是jQuery如此受欢迎的原因之一。 因此,要保持一个插件的chainability,必须确保插件返回this关键字。
jQuery基本扩展源码如下:
(function($){
$.fn.myPlugin= function(){
//console.log(this) //这里为jQuery对象
//下面没有将this包在$号中如$(this),因为this已经是一个jQuery对象,
//直接使用
this.html("htmltest");
//使用this.each()只是为了这个函数在最后会返回obj,可用来维护chain
returnthis.each(function(){
//在回调函数中的this为原生DOM元素,应该将其封装成jQuery对象
//var self = $(this)
//console.log(this) //这里为原生的DOM元素
//console.log(self); //封装成jQuery对象
return123;
});
}
})(jQuery);
上面使用this.each()的原因:
this调用的时走的这一步:
each: function( callback ) {
if(callback()== 123) return jQuery.each(this,callback,123)//这是我做测试专门写的
returnjQuery.each( this, callback );
},
each实现代码如下:
each: function( obj, callback,test ) {
varlength, i = 0;
if( isArrayLike( obj ) ) {
length= obj.length;
test&&console.log(1);
for( ; i < length; i++ ) {
test&&console.log(2);
if( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
break;
}else{
test&&console.log(3);
}
}
}else {
for( i in obj ) {
if( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
break;
}
}
}
test&&console.log(4);
returnobj;
},
最后走的路径是1,2,3,4所以说如果直接传递一个函数,则each的作用只是返回调用该方法时的对象。
3.通常一个插件提供了很多默认设置以及可以让用户修改参数,可以通过使用$.extend()函数来实现。通过插件提供一个默认的对象参数,并且在调用时可以传入一个对象参数,用于覆写默认设置。
提供覆盖默认参数功能的源码如下:
(function($){
$.fn.myPlugin= function(options){
varsettings = {
left:'200px',
right:'200px'
},
settings= $.extend(settings,options);
console.log(settings);
returnthis.each(function(){ 用来维护chain
});
}
})(jQuery);
//调用时可以覆写默认参数
$("body").myPlugin({'left':'300px'});
使用$.extend()来实现修改settings的原因:
jQuery.extend = jQuery.fn.extend是为了既能直接通过调用jQuery类来调用,比如$.extend(),又能通过jQuery生成的对象调用,比如$(“body”).extend()。
jQuery.extend = jQuery.fn.extend =function() {
varsrc, copyIsArray, copy, name, options, clone,
target= arguments[ 0 ] || {},
i= 1,
length= arguments.length,
deep= false;
//Handle a deep copy situation
if( typeof target === "boolean" ) {
deep = target;
//skip the boolean and the target
target= arguments[ i ] || {};
i++;
}
//Handle case when target is a string or something (possible in deep copy)
if( typeof target !== "object" && !jQuery.isFunction( target )) {
target= {};
}
//extend jQuery itself if only one argument is passed
if( i === length ) {
target= this;
i--;
}
for( ; i < length; i++ ) {
//Only deal with non-null/undefined values
if( ( options = arguments[ i ] ) != null ) {
//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 {
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
returntarget;
};
综上所述,如果$.extend(obj1,obj2),则会将obj2的值覆盖obj1的值,若obj1中不存在这个属性的话,会直接加到obj1中。
jQuery.extend(
{ name: “John”, location: { city: “Boston”} },
{ last: “Resig”, location: { state: “MA” }}
);
// 结果: => { name:“John”, last: “Resig”, location: { state: “MA” } }
补:若第一个参数传入true,然后后面传递两个对象:
jQuery.extend( true,
{ name: “John”, location: { city: “Boston”} },
{ last: “Resig”, location: { state: “MA” }}
);
// 结果:=> { name:“John”, last: “Resig”, location: { city: “Boston”, state: “MA” } }
4.可以使用jQuery. data()函数用于在当前jQuery对象所匹配的所有元素上存取数据。
5.不要在一个插件中声明好几个$.fn.function_name。最容易理解的方法是在插件的这个方法中声明需要使用的所有属性和方法。