2026世界杯_2004年世界杯 - 1606811.com

首页 > 击剑世界杯 > jQuery封装详解

jQuery封装详解

早几年学习前端,大家都非常热衷于研究jQuery源码。我还记得当初从jQuery源码中学到一星半点应用技巧的时候常会有一种发自内心的惊叹,“原来JavaScript居然可以这样用!”

虽然随着前端的发展,另外几种前端框架的崛起,jQuery慢慢变得不再是必须,因此大家对于jQuery的热情低了很多。但是许多从jQuery中学到的技巧用在实践中仍然非常好用。简单的了解它也有助于我们更加深入的理解JavaScript。

这里我们把jquery的实现作为一个学习案例,帮助我们进一步掌握面向对象的使用。也为有兴趣的朋友,进一步学习jquery源码一个铺垫,算是一个简单的抛砖引玉。

使用jQuery时,我们通常会这样写:

// 声明一个jquery实例

$('.target')

// 获取元素的css属性

$('.target').css('width')

// 获取元素的微信信息

$('target').offset()

咦?很奇怪,和普通的对象实例不太一样,new关键字哪里去了?$符号又是什么?那么,带着这些疑问,我们来实现一个简化版的jquery库。

首先,一个库就是一个单独的模块,因此使用自执行函数的方式模拟一个模块。

(function() {

// do something

});

第二步,我们能够在全局直接调用jquery,说明jquery被挂载在了全局对象上。因此当我们在模块中对外提供接口时,可以采取window.jQuery的方式。

var jQuery = function() {}

// ...

window.jQuery = jQuery

我们在使用时,并没有用jQuery,而是使用了$, 其实仅仅只是多加了一个赋值操作。

window.$ = window.jQuery = jQuery

但是我们在使用时,直接使用$,也就是说直接调用了构造函数jQuery来创建了一个实例,而没有使用new。但是我们知道,创建一个实例new关键字肯定是必不可少的。因此说明new的操作被放在了jQuery方法中来实现。而jQuery也并不是真正的构造函数。

前面一节的学习我们知道,每一个函数都可能是任何角色,因此jQuery内部的实现正是利用了这一点,在具体实现时,改变了内部某些函数的prototype指向。先看实现代码,再来一步步分析。

;

(function(ROOT) {

// 构造函数

var jQuery = function(selector) {

// 在该方法中直接返回new过的实例,因此这里的init才是真正的构造函数

return new jQuery.fn.init(selector);

}

jQuery.fn = jQuery.prototype = {

constructor: jQuery,

version: '1.0.0',

init: function(selector) {

var elem, selector;

elem = document.querySelector(selector);

this[0] = elem;

// 在jquery中返回的是一个由所有原型属性方法组成的数组,我们这里做了简化,直接返回this即可

return this;

},

// 在原型上添加一堆方法

toArray: function() {},

get: function() {},

each: function() {},

ready: function() {},

first: function() {},

slice: function() {}

// ... more

}

// 让init方法的原型,指向jQuery的原型

jQuery.fn.init.prototype = jQuery.fn;

ROOT.jQuery = ROOT.$ = jQuery;

})(window);

在上面的实现中,首先在jQuery构造函数中声明了一个fn属性,并将其指向了原型jQuery.prototype。随后在原型对象中添加了init方法。

jQuery.fn = jQuery.prototype = {

init: function() {}

}

之后又将init的原型,指向了jQuery.prototype.

jQuery.fn.init.prototype = jQuery.fn;

而在构造函数jQuery中,则返回了init的实例对象。

var jQuery = function(selector) {

return new jQuery.fn.init(selector);

}

最后对外暴露接口时,将字符$与方法jQuery对等起来。

ROOT.jQuery = ROOT.$ = jQuery;

因此当我们使用$('#test')创建一个jQuery实例时,实际上是调用的jQuery('#test')创建的一个init实例。这里正在的构造函数是原型中init方法。

下面用图例展示下这中间的逻辑变化。

扩展方法

我们在使用jQuery时还知道,jQuery提供了两个扩展接口来帮助我们自定义jQuery的方法。我们通常称我们自定义的jQuery方法为jQuery插件。那么这两个扩展方法是如何实现的呢?在上面的实现基础上我们继续添加代码,如下。

;

(function(ROOT) {

// 构造函数

var jQuery = function(selector) {

// 在该方法中直接返回new过的实例,因此这里的init才是真正的构造函数

return new jQuery.fn.init(selector);

}

jQuery.fn = jQuery.prototype = {

constructor: jQuery,

version: '1.0.0',

init: function(selector) {

var elem, selector;

elem = document.querySelector(selector);

this[0] = elem;

// 在jquery中返回的是一个由所有原型属性方法组成的数组,我们这里做了简化,直接返回this即可

return this;

},

// 在原型上添加一堆方法

toArray: function() {},

get: function() {},

each: function() {},

ready: function() {},

first: function() {},

slice: function() {}

// ... more

}

// 让init方法的原型,指向jQuery的原型

jQuery.fn.init.prototype = jQuery.fn;

// 实现jQuery的两种扩展方法

jQuery.extend = jQuery.fn.extend = function(options) {

// 在jquery源码中会根据参数不同进行不同的判断,我们这里假设只有一种方式

var target = this;

var copy;

for(name in options) {

copy = options[name];

target[name] = copy;

}

return target;

}

// jQuery中利用上面实现的扩展机制,添加了许多方法,其中

// 添加静态扩展方法,即工具方法

jQuery.extend({

isFunction: function() {},

type: function() {},

parseHTML: function() {},

parseJSON: function() {},

ajax: function() {}

// ...

})

// 添加原型方法

jQuery.fn.extend({

queue: function() {},

promise: function() {},

attr: function() {},

prop: function() {},

addClass: function() {},

removeClass: function() {},

val: function() {},

css: function() {}

// ...

})

ROOT.jQuery = ROOT.$ = jQuery;

})(window);

在上面的代码中,我们通过下面的方式简单的实现了两个扩展方法。

jQuery.extend = jQuery.fn.extend = function(options) {

// 在jquery源码中会根据参数不同进行很多判断,我们这里就直接走一种方式,所以就不用判断了

var target = this;

var copy;

for(name in options) {

copy = options[name];

target[name] = copy;

}

return target;

}

要理解它的实现,首先要明确的知道内部this的指向。相信学习过前面的章节对于this的掌握已经不是问题了。传入的参数options对象是一个key-value模式的对象。我们通过for in遍历options,将key作为新的属性,value作为该属性对应的新方法,分别添加到jQuery与jQuery.fn中。

也就是说,当我们通过$.extend扩展jQuery时,方法被添加到了静态方法中,而当我们通过$.fn.extend扩展jQuery时,方法被添加到了原型对象中。

静态方法可以直接调用,因此常常也被称为工具方法。例如:

$.ajax()

$.isFunction()

$.each()

//...

原型方法则必须通过声明的实例才能调用。

$('#test').css();

$('#test').attr();

// ...




如何轻松恢复vivo手机出厂设置?一步步教你!
【心得】悲慘武器介紹系列:ETHER DAGGERS(蒼穹匕首) @Warframe 哈啦板