jquery核心功能分析(带图解)
整体架构
jquery框架的核心就是从HTML文档中匹配元素并对其执行操作、
例如:
$().find().css()
$().hide().html(‘….’).hide().
从上面的写法上至少可以发现2个问题
1. jQuery对象的构建方式
2 .jQuery方法的调用方式
分析一:jQuery的无new构建
JavaScript是函数式语言,函数可以实现类,类就是面向对象编程中最基本的概念
var aQuery = function(selector, context) {
//构造函数
}
aQuery.prototype = {
//原型
name:function(){},
age:function(){}
}
var a = new aQuery();
a.name();
复制代码
这是常规的使用方法,显而易见jQuery不是这样玩的
jQuery没有使用new运行符将jQuery显示的实例化,还是直接调用其函数
按照jQuery的抒写方式
$().ready()
$().noConflict()
要实现这样,那么jQuery就要看成一个类,那么$()应该是返回类的实例才对
所以把代码改一下:
var aQuery = function(selector, context) { return new aQuery(); } aQuery.prototype = { name:function(){}, age:function(){} }
通过new aQuery(),虽然返回的是一个实例,但是也能看出很明显的问题,死循环了!
那么如何返回一个正确的实例?
在javascript中实例this只跟原型有关系
那么可以把jQuery类当作一个工厂方法来创建实例,把这个方法放到jQuery.prototye原型中
var aQuery = function(selector, context) { return aQuery.prototype.init(); } aQuery.prototype = { init:function(){ return this; } name:function(){}, age:function(){} }
当执行aQuery() 返回的实例:
很明显aQuery()返回的是aQuery类的实例,那么在init中的this其实也是指向的aQuery类的实例
问题来了init的this指向的是aQuery类,如果把init函数也当作一个构造器,那么内部的this要如何处理?
var aQuery = function(selector, context) { return aQuery.prototype.init(); } aQuery.prototype = { init: function() { this.age = 18 return this; }, name: function() {}, age: 20 } aQuery().age //18
这样的情况下就出错了,因为this只是指向aQuery类的,所以需要设计出独立的作用域才行
jQuery框架分隔作用域的处理
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor ‘enhanced’
return new jQuery.fn.init( selector, context, rootjQuery );
},
很明显通过实例init函数,每次都构建新的init实例对象,来分隔this,避免交互混淆
那么既然都不是同一个对象那么肯定又出现一个新的问题
例如:
var aQuery = function(selector, context) { return new aQuery.prototype.init(); } aQuery.prototype = { init: function() { this.age = 18 return this; }, name: function() {}, age: 20 } //Uncaught TypeError: Object [object Object] has no method 'name' console.log(aQuery().name())
抛出错误,无法找到这个方法,所以很明显new的init跟jquery类的this分离了
怎么访问jQuery类原型上的属性与方法?
做到既能隔离作用域还能使用jQuery原型对象的作用域呢,还能在返回实例中访问jQuery的原型对象?
实现的关键点
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
通过原型传递解决问题,把jQuery的原型传递给jQuery.prototype.init.prototype
换句话说jQuery的原型对象覆盖了init构造器的原型对象
因为是引用传递所以不需要担心这个循环引用的性能问题
var aQuery = function(selector, context) { return new aQuery.prototype.init(); } aQuery.prototype = { init: function() { return this; }, name: function() { return this.age }, age: 20 } aQuery.prototype.init.prototype = aQuery.prototype; console.log(aQuery().name()) //20
百度借网友的一张图,方便直接理解:
fn解释下,其实这个fn没有什么特殊意思,只是jQuery.prototype的引用
分析二:链式调用
DOM链式调用的处理:
1.节约JS代码.
2.所返回的都是同一个对象,可以提高代码的效率
通过简单扩展原型方法并通过return this的形式来实现跨浏览器的链式调用。
利用JS下的简单工厂模式,来将所有对于同一个DOM对象的操作指定同一个实例。
这个原理就超简单了
aQuery().init().name()
分解
a = aQuery();
a.init()
a.name()
把代码分解一下,很明显实现链式的基本条件就是实例this的存在,并且是同一个
aQuery.prototype = { init: function() { return this; }, name: function() { return this } }
所以我们在需要链式的方法访问this就可以了,因为返回当前实例的this,从而又可以访问自己的原型了
aQuery.init().name()
优点:节省代码量,提高代码的效率,代码看起来更优雅
最糟糕的是所有对象的方法返回的都是对象本身,也就是说没有返回值,这不一定在任何环境下都适合。
Javascript是无阻塞语言,所以他不是没阻塞,而是不能阻塞,所以他需要通过事件来驱动,异步来完成一些本需要阻塞进程的操作,这样处理只是同步链式,异步链式jquery从1.5开始就引入了Promise,jQuery.Deferred后期在讨论。
您可能感兴趣的文章:
jquery核心功能分析(带图解)
jquery源码-核心源码结构
浅析jquery的js图表组件highcharts
JQuery Tree 插件 zTree
php框架底层源码怎么看
jQuery源码分析-03构造jQuery对象-源码结构和核心函数
python数据分析师要学什么
jQuery源码分析系列
jQuery的UI插件 Smart UI
H5设计时的小技巧总结