前言:在这mvvm模式盛行的今天,很多人觉得没必要去了解jquery源码,而我并不认同以上的说法。jquery对javaScript进行了封装使其更加完善,jquery的源码中更是能看到对js原生方法的完美运用,还能学到很多没见过的操作JavaScript的技巧。简单的说,学习源码能让JavaScript使用基础更扎实。
学习jquery源码需解决的几个问题。
①、jquery是如何做到里面定义的变量不暴露在全局,而且只暴露出来一个$操作符跟一个jQuery给我们调用。
②、jquery是如何做到不运用到new就可以实例化jquery对象的。
③、jquery是如果做到链式操作的。
一、问题①
我们无法直接访问jquery里面定义的变量,但是通过$操作符或者jQuery就可以进行访问了。
(function(window,undefined){ //第二个形参undefined是为了里面出现的变量名为undefined的变量值真的为undefined,而不是其他值 var jQuery = function(){ //构造函数 }; window.jQuery = window.$ = jQuery; })(window);
利用匿名函数自执行,来形成全局无法直接访问的函数作用域,然后将全局的window,通过传参的方式传入到该函数作用域中。最后通过window.jQuery = jQuery,window.$ = jQuery的方式,将jQuery构造函数暴露出去。这样我们就可以通过jQuery和$访问该函数作用域里变量了。
二、问题②
jquery是如何做到不运用到new就可以实例化jquery对象的。
function Person(name,age){ this.init(name,age); }; Person.prototype= { init: function(name,age){ this.name = name; this.age = age; }, sayName: function(){ console.log('姓名: '+ this.name); }, sayAge: function(){ console.log('年龄: '+ this.age); } }; var nick = new Person('nick',18); //实例化对象 nick.sayName(); nick.sayAge();
JavaScript中实例化一个对象需要通过new一个构造函数的方式是实现。而在jquery中我们可以直接通过类似$('.box')的方式直接实例出一个jQuery对象,并通过$('.box').css()的方式直接调用对象方法。这是怎么做到的。
现在来模拟jQuert中实现不用new实例化对象的写法
(function(window,undefined){ var jQuery = function(name,age){ return new jQuery.prototype.init(name,age); }; jQuery.prototype = { init: function(name,age){ this.name = name; this.age = age; }, sayName: function(){ console.log('姓名: '+this.name); }, sayAge: function(){ console.log('年龄: '+this.age); } }; jQuery.prototype.init.prototype = jQuery.prototype; window.jQuery = window.$ = jQuery; })( window ); var nick = $('nick',18); nick.sayName(); nick.sayAge(); $('freddy',23).sayName(); $('freddy',23).sayAge();
输出结果:
这样也就实现了不用再外面用new就可以实例化对象了。其中比较抽象的就是
jQuery.prototype.init.prototype = jQuery.prototype;
了解过prototype也就知道,对象的实例化跟prototype原型密不可分。这里是把jQuery.prototype.init.protype的指向指回了jQuery.prototype。
我们在看回jquery源码中的写法
(function(window,undefined){ var jQuery = function(selector, context){ return new jQuery.fn.init(selector, context, rootjQuery); }; jQuery.fn = jQuery.prototype = { init: function(selector, context, rootjQuery){ } } jQuery.fn.init.prototype = jQuery.fn; window.jQuery = window.$ = jQuery; })( window );
跟我们模拟的写法稍有不同的是,他让jQuery.fn = jQuert.prototype = {},让jQuery.fn指向了同一个原型对象,这样操作jQuery.fn等同于操作jQuery原型对象。
三、问题③
链式操作
(function(window,undefined){ var jQuery = function(name,age){ return new jQuery.prototype.init(name,age); }; jQuery.prototype = { init: function(name,age){ this.name = name; this.age = age; }, sayName: function(){ console.log('姓名: '+this.name); return this; //添加return this }, sayAge: function(){ console.log('年龄: '+this.age); return this; //添加return this } }; jQuery.prototype.init.prototype = jQuery.prototype; window.jQuery = window.$ = jQuery; })( window ); var nick = $('nick',18); nick.sayName().sayAge(); $('freddy',23).sayName().sayAge();像这样,return this就好啦。