深入理解javascript系列(十八):掌握物件導向(1)

Panthon發表於2019-03-01

物件導向,一個老生常談的話題,但你有沒有想過物件導向要解決什麼問題?

有一位大神說的很直接,”物件導向要解決的問題,並不是封裝、繼承和多型,而是寫程式碼的套路“。

我覺得有理,所以簡單粗暴點,今天略看下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()的原型方法和屬性嗎?

….

相關文章