从jQuery的init源代码来看原型的使用

本文探讨了jQuery如何利用原型实现类的功能,并通过分析源代码解释了为何将核心功能封装在`init`中并绑定到`$.fn`上。主要关注点在于jQuery对外只暴露一个$接口,以及通过$.fn.extend()实现插件扩展的统一。这种设计确保了优雅的调用方式和高效的内存使用。
摘要由CSDN通过智能技术生成

其实原型这个东西一直以来都觉得是一个很简单的东西。但是因为原型链的原因反而感觉原型里面真正可以说的其实是继承与如何实现真正意义上的重载。
最近看到了关于jQuery中原型的使用,反有了点新的见解。
jQuery中是怎么实现原型的。
首先,我们要对原型有一个清楚的认识,什么时候需要使用原型。现在的ES6里面加入了一个class,而class其实也就是根据原型来实现的一种语法糖,以前我们需要使用原型来实现的功能,现在可以使用class来实现了。也就是说,我们在需要类的时候使用原型

        function cla() {
            this.add = function () {}
            this.puls = function () {}
        }

而这样写,每次创建一个对象的时候都会开辟空间给add,puls函数所以我们使用原型

function cla() {
}
cla.prototype.add=function(){console.log('add');}
let a=new cla()
a.add()

这样就可以有效的节约空间了,可以看到这里我们使用了一个new,表示这些必须是new出来的对象才可以使用
而在jq中,我们可以先观察jq中是怎么使用的。

let $p=$('p')
$p.css()

这里的css就是通过prototype原型来实现的。

https://github.com/jquery/jquery/blob/master/src/core.js
中我们可以看到最后的返回值是

return jQuery;

而jQuery的返回值是

    jQuery = function( selector, context ) {

        // The jQuery object is actually just the init constructor 'enhanced'
        // Need init if jQuery is called (just allow error to be thrown if not included)
        return new jQuery.fn.init( selector, context );
    },

返回的是new jQuery.fn.init
也就是说我们执行
$(‘p’)的时候其实是返回了一个init的对象
再继续看

jQuery.fn = jQuery.prototype = {

jq的原型跟jquery.fn进行了绑定
原型里面有一些方法比如

eq: function( i ) {
        var len = this.length,
            j = +i + ( i < 0 ? len : 0 );
        return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
    },

而css这个方法是通过扩展extend进行的
这里其实会有一个疑问,为什么非要进行返回init呢?
回想一下我们对jQuery的调用。
$(‘p’)
如果我们是这样写jq的


let jq = function (selector) {
let slice = Array.prototype.slice
let dom = slice.call(document.querySelectorAll(selector))
let len = dom ? dom.length : 0
for (let i = 0; i < len; i++) {
this[i] = dom[i]
}
this.length = len
this.selector = selector || ''
}
jq.prototype = {
css() {
alert('css')
},
html() {
alert('html')
},
}
window.$ = jq

那么我们会面临一个问题,那就是我们必须是

let $p=new $('p')

这个样子,就不够优雅了,所以我们就需要返回一个new的对象,所以就把jq实际的内容都写在了init里面去了,而为什么原型绑定到fn上面呢?
这个是因为插件机制的考虑
如果我们想在外部对jq进行扩展怎么扩展,可使用
$.fn.extend()
而在内部比如css的扩展其实是使用的

jQuery.fn.extend( {

但是这个是适用于内部,我们的jq暴露出来的只有一个$符号,这个是最小暴露,所以我们在外面对jq进行扩展就不能使用css的扩展方式了
这样就需要一层媒介,也就是fn
好处是

只会对外暴露一个$接口

将插件扩展统一到$.fn这个接口方便调用

所以我们可以这样写jq

let jq = function (selector) {
return new jq.fn.init(selector)
}
jq.fn={
css(){
alert('css')
},
html(){
alert('html')
}
}
let init = jq.fn.init = function (selector) {
let slice = Array.prototype.slice
let dom = slice.call(document.querySelectorAll(selector))
let len = dom ? dom.length : 0
for (let i = 0; i < len; i++) {
this[i] = dom[i]
}
this.length = len
this.selector = selector || ''
}
init.prototype=jq.fn
window.$ = jq

进行了简化

可见,虽然原型的使用看起来很简单,但是想要设计出来合理的使用方式,还是需要琢磨的。至于为啥jq非要赋值给init再来进行扩展,这个操作我就也不是很看得懂了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值