深入理解javascript系列(十八):掌握面向对象(1)

343 阅读2分钟

面向对象,一个老生常谈的话题,但你有没有想过面向对象要解决什么问题?

有一位大神说的很直接,”面向对象要解决的问题,并不是封装、继承和多态,而是写代码的套路“。

我觉得有理,所以简单粗暴点,今天略看下jQuery的封装。

使用jQuery时,我们通常会这样写:

//声明一个JQ实例
$('.target')

//获取元素的css属性
$('.target').css('width')

//获取元素的位置信息
$('.target')

是不是与普通的对象实例不太一样,new关键字去哪了,$符合又是什么?当然咯,您肯定是知道的,现在就让我们来简化一下JQ吧。

一个库就是一个单独的模块,因此我们使用自执行函数的方式模拟一个模块。

(function() {
    // to do something
})()

既然能够在全局直接调用jQuery,则说明JQ被挂载在了全局对象上。因此当我们在模块中对外提供接口时,可以采取window.jQuery的方式。

var jQuery = function() {};

//....

window.jQuery = jQuery

我们在使用过程中,并没有使用jQuery,而是使用了$,其实只是多加了一个赋值操作。

window.$ = window.jQuery = jQuery

在使用过程中直接使用$,其实相当于直接调用构造函数jQuery创建了一个实例,而没有使用new。但是创建一个实例时,new关键字是必不可少的,由此说明new的操作被放在了jQuery方法中来实现了,而jQuery并不是真正的构造函数,

我们应该知道,函数可以扮演不少角色,对象啊,类啊...JQ内部的实现其实就是利用这个,在具体实现时,改变内部某些函数的prototype指向。下面我们就来看看实现代码把。

(function(ROOT) {
    
    //构造函数
    var jQuery = function(selector) {
        //在该方法中直接返回new创建的实例,
        //因此这里的init才是真正的构造函数

        return new jQuery.fn.init(selector);
    }

    jQuery.fn = jQuery.prototype = {
        constructor: jQuery,
        version:'xxx',
        init: function(selector) {
            var elem, selector;
            elem = document.querySelector(selector);
            this[0] = elem;

            return this;
        },
             //在原型上添加一堆方法     ...
    }

    //让init方法的原型指向jQuery的原型
    jQuery.fn.init.prototype = jQuery.fn;
    
    ROOT.jQuery = ROOT.$ = jQuery;

})(window)

在上面的实现中,首先在jQuery构造函数中声明了一个fn属性,并将其指向了jQuery的原型。随后在原型对象上添加了init方法。

jQuery.fn = jQuery.prototype = {
    init: function() {}
}

之后又将init的原型指向了jQuery.prototype.

  jQuery.fn.init.prototype = jQuery.fn;

而在构造函数jQuery中,则返回了init的实例对象。

 var jQuery = function(selector) {
        return new jQuery.fn.init(selector);
    }

最后对外暴露接口时,将字符串$与方法jQuery对等起来。

 ROOT.jQuery = ROOT.$ = jQuery;

因此当使用$('xxxx')创建一个jQuery实例时,实际上调用的是jQuery('xxxx')创建的一个init实例。这里正是构造函数原型上的init方法。

其实,到这里我是有很多疑问的。

1、你知道为什么要为自执行函数设置参数window吗?

2、你知道为什么要在构造函数jQuery内部用new创建并返回另一个构造函数的实例吗?

3、你知道为什么要jQuery.fn = jQuery.prototype,设置jQuery.fn 指向构造函数jQuery()的原型对象jQuery.prototype吗?

4、你知道为什么能在构造函数jQuery.fn.init()的实例上调用构造函数jQuery()的原型方法和属性吗?

....