jQuery $ 原理及extend函数源码实现

栏目: jQuery · 发布时间: 4年前

内容简介:jQuery在页面直接通过$调用一开始的思考是这样实现,打印$可以直接打印出jQuery构造函数,但是当创建jQuery实例对象的时候,会进入一个死循环如何避免这一问题呢,这里要用到共享原型的设计,将jQuery原型对象上面扩展一个init方法,该方法的原型对象指向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的原型对象

(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实例对象也能访问该方法

(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有很多种调用方法

//任意对象扩展
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.extend

(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跟false

(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: "男"}}
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Introduction to Tornado

Introduction to Tornado

Michael Dory、Adam Parrish、Brendan Berg / O'Reilly Media / 2012-3-28 / USD 23.99

Tornado is a scalable, non-blocking web server and web application framework written in Python. It is also light-weight to deploy, fun to write for, and incredibly powerful. Tornado was written with p......一起来看看 《Introduction to Tornado》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

URL 编码/解码
URL 编码/解码

URL 编码/解码