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: "男"}}
复制代码
相关文章
相关标签/搜索