如题,为什么要这么做呢?为了配合上面的语句,还得加上下面这句很绕的语句:
jQuery.fn.init.prototype = jQuery.fn;
为什么不能这么干呢?
(function(){
var jQuery = function(){
return new F();
};
var F = function(){
return this;
};
F.fn = F.prototype = {
jquery : 1.0,
test : function(){
console.log('test');
return this;
}
};
jQuery.fn = jQuery.prototype = F.prototype;
window.jQuery = window.$ = jQuery;
})();
var a = $('body').test('li');
console.log('');
$.fn.extend = function(){console.log('extended');}
a.extend();
这样层次清晰,而且兼顾到插件扩展,求大神赐教。
两者的效果区别只在于,jquery多做了把F挂到$.fn上。所以你的代码加一句jQuery.fn.init = F;如楼上说,就等价了。这样的好处是在访问不到F的地方,可以调用jQuery.fn.init。
@nighca 当然,如果要扩展jQuery,必须加上jQuery.extend = F.extend = F.fn.extend = function extend(){};如果是为了避免还有可能出现的这种情况,那么可以解释为什么要把F挂到jQuery.fn上
- 其实楼主的F和jQuery.fn.init是相等的; 实现功能是和jq一样的, 只是jq的把构造函数放进原型;
- 如果非要说原因, 个人理解jq这样写整体结构清晰, 先是入口构造函数,紧跟着是原型部分(原型里面init是初始化), 但是不好理解;
- 乍一看确实挺绕, 我也是看了好久才明白怎么回事
jQuery = function( selector, context ) { return new jQuery.fn.init( ); } jQuery.fn=JQuery.prototype = { init: function() {}, … }
- 最后重置原型, 和楼主的 jQuery.prototype = F.prototype;一个意思 jQuery.fn.init.prototype = jQuery.fn;
@jeffZhong 其实我也明白我的代码和jQuery的代码其实是相同的,只是把F替换成了jQuery.fn.init,但是疑问的是为什么要这么干,因为这样看起来很绕。 我的理解是为了extend方法的代码层次清晰,因为现在没办法在外面访问F,所以,要达到扩展jQuery本身的目的,需要添加这么一句:
jQuery.extend = F.extend = F.fn.extend;
但是这样做破坏了原本代码的层次,把jQuery和F混合了,所以直接吧F挂到jQuery.fn.init上
@yu521088 将F的引用挂在fn上,也就是间接地挂在$这个对外暴露的变量上。那么在外部就可以访问到并使用F,比如F.apply(obj),或者obj instance of F,总之,这个函数作为jQuery中重要的一个函数(所有jQuery对象的constructor),大量重要逻辑在其中,将其暴露出来是可能发挥出一些作用的。以上为个人理解。
你后面的话我没看懂…
@yu521088 jq要扩展方法直接这样也不麻烦:
jQuery.extend = jQuery.fn.extend=function(){ }
jQuery.extend是扩展到jquery上, jQuery.fn.extend扩展到jquery实例上,也就是原型上面的 而你的也跟jq一样:
jQuery.extend = jQuery.fn.extend; 不需要这样: jQuery.extend = F.extend = F.fn.extend;
这样就可以了
@nighca 其实jQuery.extend = F.extend;这样就可以对外暴露F这个变量了吧。你要对F做的扩展都可以通过jQuery.extend实现啊。
我后面那句话是想说,如果有大量的需要在内部扩展F的语句,比如:
F.extend({
one: ...
});
F.extend({
two: ...
});
F.extend({
three: ...
});
那为了把这些方法暴露出来,需要同时扩展jQuery和F:
var one = {
one: ...
},
two = {
two: ...
},
three = {
three: ...
};
jQuery.extend(one);
F.extend(one);
jQuery.extend(two);
F.extend(two);
jQuery.extend(three);
F.extend(three);
@nighca 其实就是怎么暴露F的问题,jQuery是把F通过jQuery.fn.init暴露了,依我现在的实现,每一次扩展F,必须同时扩展jQuery。其实也可以这么做吧:
F.fn.extend = function(){
// 现在jQuery的extend方法
}
jQuery.extend = function(){
F.fn.extend.apply(F, arguments.slice);
}
@jeffZhong 我觉得你说的方法也不对,因为这样的话你调用$.extend() 其实扩展的是jQuery,而不是F,我觉得更好的方法是:
F.fn.extend = function(){
// 现在jQuery的extend方法
}
jQuery.extend = function(){
F.fn.extend.apply(F, arguments.slice);
}
这样一来,所有对jQuery的扩展,实质上是对F的扩展
其实jQuery.extend = F.extend;这样就可以对外暴露F这个变量了吧。你要对F做的扩展都可以通过jQuery.extend实现啊。
做不到吧,比如我在外部(jQuery使用者角度)这样用:
var a = jQuery.fn.init.apply({});
如果没挂在jQuery.fn上,怎么拿得到这个函数啊。
另外,我还是没理解你的意思,jQuery里边现在有三个东西:jQuery(即$,返回值为一个Constructor的实例的函数), Constructor(jQuery对象的构造函数,记为Constructor,即F,亦即jQuery.fn.init),jQuery.fn(是Constructor的prototype)。
jQuery的主要扩展就两个地方:
-
往jQuery上挂
jQuery.extend({ xxx: function(){} })
使用方式:$.xxx()或jQuery.xxx()
-
往jQuery.fn上挂
jQuery.fn.extend({ xxx: function(){} })
使用方式:$(‘div’).xxx()
并没有需要扩展F(Constructor)的场景啊。
@nighca 恩
其实jQuery.extend = F.extend;这样就可以对外暴露F这个变量了吧。你要对F做的扩展都可以通过jQuery.extend实现啊。
这里是我想错了。
但是,从框架提供者的角度,更应该避免用户以下面这种方式调用的情况吧:
var a = jQuery.fn.init.apply({});
jQuery 需要扩展两个地方我理解,现在jQuery的代码是通过jQuery.extend和jQuery.fn.extend方式实现。 那么,要达到这个目的,我可以在我的代码里这么写:
jQuery.extend = F.fn.extend = function(){
// current jquery 'extend' method
}
这样,在外部,我既可以通过$.extend 来扩展jQuery,也可以通过$.fn.extend来扩展jQuery对象。
至于我说的要扩展F的情况,我的想法是这样的,可能有点洁癖的感觉: 我最开始定义的jQuery变量只是暴露给外部的一个接口,而我真正的jQuery对象是通过new F() 生成的,而且所有的jQuery对象的方法都是定义在F.prototype里面。所以像需要对外暴露的jQuery方法,比如:$.ajax, $.data 这些方法,我希望他们是定义在内部的F下,而不是定义在对外暴露的jQuery变量下,因此我希望调用$.extend()的时候,他是对F进行扩展,而不是对jQuery进行扩展。不知道这样的解释你能明白吗?
@yu521088 要明白jQuery和jQuery.fn的区别 你上面jQuery.extend = function(){} 扩展的当然是jQuery, 你要扩展jqeury的实例(也就是F)就必须这样
jQuery.fn.extend=function(){…}; // 认真看,中间多了个fn
用你的代码: 同时扩展到jquery和jquery实例(即F)上面
$.extend=$.fn.extend = function(){ console.log(this); console.log(‘extended’); } $(‘body’).extend();//这个方法是jqeury的实例,是F.fn上面的 this的结果是: F $.extend();//这个方法是jquery本身 this的结果是: jQuery
其实上面就对应了我们jquery中不同类型的api 比如: $.ajax() 和 $(‘#id’)的区别, 前者对应的是jquery.extend, 后者对应jquery.fn.extend
@jeffZhong ,首先,我明白$和$.fn的区别,也明白$.extend和$.fn.extend的区别。你的这段代码:
jQuery.fn.extend=function(){…}; // 认真看,中间多了个fn 等同于我写的: F.fn.extend = function(){ // 现在jQuery的extend方法 } 因为在jQuery.fn = F.fn。
而我要同时满足$.extend和$.fn.extend,我可以这么实现:
jQuery.extend = F.fn.extend = function(){}; 这样,在外部,我既可以$.extend({’ajax’: function(){}})来扩展jQuery实现$.ajax,也可以$.fn.extend({’some’:function(){}})来扩展jQuery.fn实现$(‘#id’).some();
但是这么做,当我们调用$.extend的时候,实际上是扩展的内部的jQuery这个变量,而我觉得更合理的代码实现应该做到这样:在外部调用$.extend的时候,不应该是对内部jQuery变量的扩展,而是对F的扩展。所以才有了这段代码:
jQuery.extend = function(){ F.fn.extend.apply(F, arguments.slice); }
还有,下面这段代码中的this分别是F和jQuery是正确的逻辑啊:
$.extend=$.fn.extend = function(){
console.log(this);
console.log('extended');
}
$('body').extend();//这个方法是jqeury的实例,是F.fn上面的
this的结果是: F
$.extend();//这个方法是jquery本身
this的结果是: jQuery
@jeffZhong 其实我只是单纯的不明白为什么jQuery要把用这么绕的方式实现:
new jQuery.fn.init();
jQuery.fn.init.prototype = jQuery.fn;
@kingapple 子类可继承是一方面。另一方面是,定义一个Man类,每个Man实例都会有自己的名字,年龄,性别,这些属性对每个Man实例都是不同的,不能公用。但是像run(), eat()这些方法,可以是每个Man实例都共享的。
@yu521088 理解为你是要禁用扩展jquery本身的功能, 如果别人真要扩展在jquery上面, 不用你的
jQuery.extend({aa:function(){...}})
这个方法,直接向下面这样扩展呢
$.aa=function(){...}
@yu521088 还有本来人家jq中 $.extend就是扩展jquery本身, $.fn.extend就是扩展jquery实例, 而我只是不理解你干嘛要禁用掉扩展jq本身, 两个都留着多好, 想扩展哪个就扩哪个 :)
@jeffZhong 恩,好像这个解释比较说的通,如果用这样的方法扩展$: `$.extend({’a’:function(){}}); 而用
$.b = function(){
//这里访问不到this.a
}
在b里就访问不到this.a 了,因为这里的this是jQuery,而用extend扩展的是F。
但是我也可以这么干啊:
jQuery.extend = F.fn.extend = function(){}
这样,扩展jQuery就可以了,可以用$.extend 也可以用$.newMethod。
@yu521088 但是你要知道fn是jquery下面的属性,在外部是可以访问得到的, 而你的F是内部的, 在外面是没法访问到的, 如果我外部扩展类库的方法是可以的
$.fn.extend({a:function(){...}})
而你的
F.fn.extend(a:function(){...})
你外面根本不能这样调,会报错的,因为F是内部的变量 你的类库总不能每次人家要扩展插件了,都要在你内部扩展吧
@jeffZhong 内部有一句话
jQuery.fn = jQuery.prototype = F.prototype;
所以在外面我可以通过$.fn.extend(a:function(){…})来扩展F.fn
还有本来人家jq中 $.extend就是扩展jquery本身, $.fn.extend就是扩展jquery实例, 而我只是不理解你干嘛要禁用掉扩展jq本身, 两个都留着多好, 想扩展哪个就扩哪个 :)
我的想法是内部的jQuery这个变量是暴露给外面的桥梁,也就是说这个jQuery变量可以随便取什么名字,比如cQuery,而jQuery对象其实是F的实例,所有实例的方法代码其实都在F.fn下,所以我这里的F其实应该就是John大神代码里的jQuery变量,所以我想让所有对jQuery本身的扩展放在F下面 :) 感觉有点代码洁癖的样子,恩,是这样的 LOL
@yu521088 也就是说本来就已经实现了的功能, 像jq那样
$.fn.extend({a:function(){...}}); 扩展实例
$.extend({a:function(){...}}); 扩展本身
那你还什么不满足,你这是要闹那样呢?
最近我也在读jquery源码,也思考了这个问题。这个实现方式感觉很晦涩。 我也百度了不少文章没有找到讲的特别清楚的。 从这个问题还可以引申出 为什么不用 jQuery.init = function(){//构造函数 },应该可以实现相同的功能。并且同样可以暴露到全局作用域。 大家应该知道js中的prototype 主要是为了实现继承。那么jQuery.fn.init可以被所有的jQuery实例对象调用。 另外 我在这个地址找到了正确答案:http://stackoverflow.com/questions/18782973/why-is-the-init-function-in-jquery-prototype-and-not-in-jquerys-closure