作者:myprelude@github
原文链接: https://myprelude.github.io
转载请注明出处,保留原文链接和作者信息。
jQuery / $
$('div').css({background:'red'})
var jQ = new jQuery('div')
jQ.css({width:'500px'}).show()
什么Vue,React,Angular,老夫就jQuery一把梭子走天下。我们在使用jQuery给我们带来快发快感时,是否思考过它是如何实现的?为什么可以实例化jQuery又可以直接调用jQuery?jQuery是如何解决命名冲突的?….等等
今天就从我理解的思维开始搭建一个简单的jQuery,让我们从走进大神的世界。
构建独立的作用域
(function(window,document){
function jQuery () {
}
jQuery.version = '1.0.0';
window.jQuery = window.$ = jQuery;
})(window,document)
// test code
console.log($.version) // 1.0.0
console.log(jQuery.version) // 1.0.0
实现元素jQuery主体函数
function jQuery (tag) {
var Tag = document.querySelectorAll(tag);
this.nodes = [];
this.each(Tag,function(val,key){
this.nodes.push(val)
})
}
jQuery.prototype = {
contrustor:jQuery,
version:'1.0.0',
each:function(arr,callback){
for(var i=0;i<arr.length;i++){
callback.call(this,arr[i],i)
}
},
css:function(){
// this.jqDom.style =
console.log('set css function ...')
}
}
new jQuery('div') // [div.content]
new jQuery('div').version // 1.0.0
new jQuery('div').css() // set css function ...
如何实现无new 实例化
在实际开发中,每次都要通过new jQuery()来实现实例化太麻烦了,有没有好的方法直接 jQuery()呢?
function jQuery (tag) {
if( !(this instanceof jQuery) ){ // 关键判断当前this
return new jQuery(tag)
}
var Tag = document.querySelectorAll(tag);
this.nodes = [];
this.each(Tag,function(val,key){
this.nodes.push(val)
})
}
jQuery.prototype = {
contrustor:jQuery,
version:'1.0.0',
each:function(arr,callback){
for(var i=0;i<arr.length;i++){
callback.call(this,arr[i],i)
}
},
css:function(){
// this.jqDom.style =
console.log('set css function ...')
}
}
new jQuery('div').css() // set css function ...
jQuery('div').css() // set css function ...
我们来看看jQuery是如何实现无new 实例化
function jQuery(tag){
return new jQuery.prototype.init(tag) // 关键 1
}
jQuery.prototype = {
constructor:jQuery,
init:function(tag){
var Tag = document.querySelectorAll(tag);
this.nodes = [];
this.each(Tag,function(val,key){
this.nodes.push(val)
})
},
each:function(arr,callback){
for(var i=0;i<arr.length;i++){
callback.call(this,arr[i],i)
}
},
css:function(){
console.log('set css function ...')
}
}
jQuery.prototype.init.prototype = jQuery.prototype; // 关键 2
new jQuery('div').css() // set css function ...
jQuery('div').css() // set css function ...
可以看出来jQuery并不是通过instanceof来做判断,它同时实例化原型属性上的init方法实现的。
return new jQuery.prototype.init(tag)
当我们调用jQuery(‘div’)时,其实是先实例化jQuery.prototype.init,这样我们虽然可以实现无new但是又有一个问题出现,现在我们是如何拿到jQuery.prototype上的方法呢?这里jQuery做的方法就很巧妙。。
jQuery.prototype.init.prototype = jQuery.prototype;
如上:将jQuery.prototype.init的原型指向jQuery的原型。为啥这样我们就可以拿到jQuery原型的方法呢?这里我们需要知道new
做了什么。
new到底做了什么
var obj = {};
obj.__proto__ = `构造函数`.prototype
`构造函数`.call(obj)
return obj
简单的说就是生成一个指向构造函数原型的对象,从而调用构造函数原型的方法,构造函数原型中的this指向该对象。
根据上面的逻辑来套
jQuery('div') => new jQuery.prototype.init
||
||
jQuery.prototype.init.prototype => jQuery.prototype
jQuery('div')
拿到 jQuery.prototype.init
原型上的方法,其原型是指向 jQuery.prototype
,这样就行程了一个引用连。
如何实现jQuery方法的拓展
function jQuery(tag){
return new jQuery.prototype.init(tag)
}
jQuery.extend = function(obj,tager){
for(var k in obj){
tager?target[k]:jQuery.prototype[k] = obj[k]
}
}
jQuery.extend({hide:function(){console.log('hide')}})
jQuery('div').hide() // hide
如何解决jQuery在全局中命名冲突问题
_jQuery = window.jQuery, // 如果jQuery/$命名冲突像保存存在的
_$ = window.$,
jQuery.noConflict = function( deep ){ // 调用这个方法重写拿到之前储存的jQuery
if ( window.$ === jQuery ) {
window.$ = _$;
}
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
}
如何导出jQuery
(function(window){
// AMD // CMD
if( typeof define ==='function' && (define.amd || define.cmd) ){
define(function(){
return jQuery
})
}else{
window.$ = window.jQuery = jQuery;
}
})(window)