jQuery $ 原理及extend函數源碼實現

jQuery建立對象

前提

jQuery在頁面直接經過$調用數組

  1. $ 就是jQuery的別稱
  2. 經過 $() 建立jQuery的實例對象

實現

(function(root){
    var jQuery = function(){
        return new jQuery()
    }
    root.$ = root.jQuery = jQuery
})(this)

console.log($)
複製代碼

一開始的思考是這樣實現,打印$能夠直接打印出jQuery構造函數,可是當建立jQuery實例對象的時候,會進入一個死循環函數

console.log($())    //不停的調用jQuery構造函數
複製代碼

如何避免這一問題呢,這裏要用到共享原型的設計,將jQuery原型對象上面擴展一個init方法,該方法的原型對象指向jQuery的原型對象ui

(function(root){
    var jQuery = function(){
        return new jQuery.prototype.init()  //返回的是init實例對象,該原型對象跟jQuery原型對象相等
    }
    jQuery.prototype = {
        init: function(){
        },
    }
    //共享原型對象
    jQuery.prototype.init.prototype = jQuery.prototype
    root.$ = root.jQuery = jQuery
})(this)
複製代碼

當再次打印出$(),返回的是init的實例對象,想要擴展jQuery方法,只須要在jQuery.prototype上面擴展方法便可,init實例對象也能訪問該方法this

(function(root){
    var jQuery = function(){
        return new jQuery.prototype.init()  //返回的是init實例對象,該原型對象跟jQuery原型對象相等
    }
    jQuery.prototype = {
        init: function(){
        },
        method: function(){
            return 123
        }
    }
    //共享原型對象
    jQuery.prototype.init.prototype = jQuery.prototype
    root.$ = root.jQuery = jQuery
})(this)

console.log($().method())   //123
複製代碼

extend

jQuery的extend有不少種調用方法spa

//任意對象擴展
var obj = $.extend({},{name: "ys"})

//往其自己擴展
$.extend({
   work: function(){}
})
jQuery.work()

//實例對象擴展
$.fn.extend({
    sex: "男"
})
jQuery().sex  //男
複製代碼

任意對象擴展

(function(root){
    var jQuery = function(){
        return new jQuery.prototype.init()  //返回的是init實例對象,該原型對象跟jQuery原型對象相等
    }
    jQuery.prototype = {
        init: function(){

        },
        method: function(){
            return 123
        }
    }
    jQuery.extend = function(){
        var targe = arguments[0] || {}
        var length = arguments.length
        var i = 1
        var option, name
        if(typeof targe !== "object"){
            targe = {}
        }
        for(;i<length;i++){
            if((option = arguments[i]) != null){
                for(name in option){
                    targe[name] = option[name]
                }
            }
        }
        return targe
    }
    //共享原型對象
    jQuery.prototype.init.prototype = jQuery.fn
    root.$ = root.jQuery = jQuery
})(this)

var obj = $.extend({sex: "男"},{name: "ys"})   //{sex: "男", name: "ys"}
複製代碼

自己擴展及實例對象擴展

實例對象擴展展只須要將jQuery.fn = jQuery.prototype 以及 jQuery.fn.extend = jQuery.extendprototype

(function(root){
    var jQuery = function(){
        return new jQuery.prototype.init()  //返回的是init實例對象,該原型對象跟jQuery原型對象相等
    }
    jQuery.fn = jQuery.prototype = {
        init: function(){

        },
        method: function(){
            return 123
        }
    }
    jQuery.fn.extend = jQuery.extend = function(){
        var targe = arguments[0] || {}
        var length = arguments.length
        var i = 1
        var option, name
        if(typeof targe !== "object"){
            targe = {}
        }
        //參數個數等於1,說明是往自身擴展
        if(i === length){
            targe = this
            i--
        }
        for(;i<length;i++){
            if((option = arguments[i]) != null){
                for(name in option){
                    targe[name] = option[name]
                }
            }
        }
        return targe
    }
    //共享原型對象
    jQuery.prototype.init.prototype = jQuery.fn
    root.$ = root.jQuery = jQuery
})(this)

var obj = $.fn.extend({sex: "男"},{name: "ys"})   //{sex: "男", name: "ys"}

//往其自己擴展
$.extend({
    work: function(){
        return '搬磚'
    }
})
console.log(jQuery.work())  //搬磚
複製代碼

進階

extend方法還接受一個deep屬性,指示是否深度合併對象,若是隻是按上面的代碼擴展對象,重複的屬性會被覆蓋,而不是合併設計

var obj1 = {
    name: "ys",
    attr: {
        age: "18"
    }
}
var obj2 = {
    name: "ys",
    attr: {
        sex: "男"
    }
}
var obj = $.extend(true, {}, obj1, obj2)

//後面得屬性會覆蓋以前的屬性
console.log(obj)    //{name: "ys", attr: {sex: "男"}}
複製代碼

如何才能對象合併而不是覆蓋,以及作到對象的深拷貝呢? 接受的第一個參數傳deep,true跟falsecode

(function(root){
    var jQuery = function(){
        return new jQuery.prototype.init()  //返回的是init實例對象,該原型對象跟jQuery原型對象相等
    }
    jQuery.fn = jQuery.prototype = {
        init: function(){

        },
        method: function(){
            return 123
        }
    }
    jQuery.fn.extend = jQuery.extend = function(){
        var targe = arguments[0] || {}
        var length = arguments.length
        var i = 1
        var deep = false
        var option, name, copy, src, copyIsArr, clone
        //深拷貝,淺拷貝
        if(typeof targe === "boolean"){
            deep = targe
            targe = arguments[1] || {}  //爲了避免改變以前的步驟,將參數第二項賦給target,而且將i改成2
            i = 2
        }
        if(typeof targe !== "object"){
            targe = {}
        }
        //參數個數等於1,說明是往自身擴展
        if(i === length){
            targe = this
            i--
        }
        for(; i < length; i++){
            if((option = arguments[i]) != null){
                for(name in option){
                    copy = option[name]
                    src = targe[name]
                    if(deep && copy && (copy instanceof Object || (copyIsArr = copy instanceof Array))){//判斷是不是深拷貝及淺拷貝,copyIsArr判斷是不是數組
                        if(copyIsArr){  //copy是數組
                            copyIsArr = false
                            clone = src && src instanceof Array ? src : []
                        } else {
                            clone = src && src instanceof Object ? src : {}
                        }
                        targe[name] = jQuery.extend(deep, clone, copy)  //遞歸調用,深拷貝
                    } else if(copy){
                        targe[name] = copy
                    }
                }
            }
        }
        return targe
    }
    //共享原型對象
    jQuery.prototype.init.prototype = jQuery.fn
    root.$ = root.jQuery = jQuery
})(this)

//兩層
var obj1 = {
    name: "ys",
    attr: {
        age: "18"
    }
}
var obj2 = {
    name: "ys",
    attr: {
        sex: "男"
    }
}
var obj = $.extend(true, {}, obj1, obj2)
console.log(obj)    //{name: "ys", attr: {age: "18", sex: "男"}}

//三層
var obj1 = {
    name: "ys",
    attr: {
        age: {
            a: 1
        }
    }
}
var obj2 = {
    name: "ys",
    attr: {
        sex: "男",
        age: {
            b: 2
        }
    }
}
var obj = $.extend(true, {}, obj1, obj2)
console.log(obj)     //{name: "ys", attr: {age: {a: 1, b: 2}, sex: "男"}}
複製代碼
相關文章
相關標籤/搜索