如题,为什么要这么做呢?为了配合上面的语句,还得加上下面这句很绕的语句:
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();
这样层次清晰,而且兼顾到插件扩展,求大神赐教。
把你的这个定义里面的F
换成jQuery.fn.init
,不就等价了吗?
@bnuhero 我的代码结构可以实现jQuery的要求了啊,为什么要把F换成jQuery.fn.init呢?这样多不直观啊
两者的效果区别只在于,jquery多做了把F挂到$.fn上。所以你的代码加一句jQuery.fn.init = F;如楼上说,就等价了。这样的好处是在访问不到F的地方,可以调用jQuery.fn.init。
我也一直有这疑问 同求
@nighca 但是没有必要访问F啊,要扩展有两种,意识jQuery.extend;二是jQuery.fn.extend。现在两者都可以被扩展啊。
@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)的场景啊。
不知道prototype除了写这么大的东西,还在其他地方用的到么?
@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进行扩展。不知道这样的解释你能明白吗?
@kingapple 没看明白
@yu521088 你平时用prototype么?
@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
@kingapple prototype用来实现继承啊
@yu521088 额,平时用到多么?
@kingapple 多啊,你要写一个类,把这个类的非公有属性放在自己的属性中,把公有的方法和属性放在prototype对象中啊
@yu521088 你看看jquery的源码就知道了,不太了解你要达到什么效果
@yu521088 你说的公有,是子类可继承的意思吧?
@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 prototype里面可以放公共变量,类似于静态变量?
@yu521088 其实你的方式实现了和jquery差不多的功能, 同时扩展插件方面也是和jq一样的效果的. , 只是解决方式不一样而已
@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是内部的变量 你的类库总不能每次人家要扩展插件了,都要在你内部扩展吧
@kingapple 对的,比如计数器
@yu521088 js的实现好蛋疼,还是Java的直观:)
@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
@kingapple 对的,这就是js神(dan)奇(teng)的地方。
@yu521088 js没有接口的概念吧?要实现复杂模式,就变成天书了:(
@yu521088 也就是说本来就已经实现了的功能, 像jq那样
$.fn.extend({a:function(){...}}); 扩展实例
$.extend({a:function(){...}}); 扩展本身
那你还什么不满足,你这是要闹那样呢?
@jeffZhong 我只是想知道jQuery为什么不像我这么干,要把F放到jQuery.fn.init下 %>_<%
@kingapple 尼玛又见到你了…真水啊…
最近我也在读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