zoukankan      html  css  js  c++  java
  • javascript-继承之jquery

    jquery 截止到当前已经3.3.1版本了,如今随着各种浏览器的盛行,前端的框架层出不穷,jquery独步天下,老夫写代码只用jquery,拿起代码就是干的辉煌时代已经过去了。

    2006 年,jQuery 的第一个版本的面世,凭借着简洁、灵活的编程风格受到了开发者的喜爱。而它本身是一个 JavaScript 框架,它的设计的宗旨是“write Less,Do More”,即倡导写更少的代码,做更多的事情。它封装了 JavaScript 常用的功能代码,提供一种简便的 JavaScript 设计模式,优化 HTML 文档操作、事件处理、动画设计和 Ajax 交互。

    从之前的风靡到如今的被抛弃,究其原因,不少前端工程师表示,对于 jQuery 来说,大量的操作 DOM 虽然方便,但是会牺牲很多页面的性能。另一方面,现阶段 React、Vue 和 Angularjs 等主流前端框架并不依赖 jQuery,都可以独立使用。况且浏览器的兼容问题越来越少,当浏览器兼容不再是问题时,jQuery 的价值就大打折扣了

    就在微软收购github 的52天,github改变也已经放弃了jquery,奇替代方案使用了原生的js:

    • 使用 querySelectorAll 来查询 DOM 节点;
    • 使用 fetch 来代替 ajax;
    • 事件处理使用了事件代理;
    • 使用 DOM 标准化写了 polyfill;
    • 使用了自定义元素。

    jquery

    假如不用,学习下还是可以的

    本文粗燥的实现jquery 的 ready、each、bind、$.fn.extend、$.extend

    初始化$

    ;(function (win) {
      var _$ = function (selector, context) {
        /**
         * 通常咱们定义一个 函数 var Fun = function(){}
         * 然后定义一个 Fun.prototype.init = function(){} 
         * 那么咱们调用init 的时候 得先要实例化对象 var f = new Fun()
         * 然后f.init()
         * 这里就省去了 var $ = new $()
         */
        return new _$.prototype.Init(selector, context);
      }
      _$.prototype = {
        //初始化$
        Init: function (selector, context) {
          this.elements = [];
          /**
           * 传入的类型是function 就执行ready事件,如果是document 就将document对象插入到this.elements
           * 主要就是判断$(document).ready  和 $(function(){}) 这两种的ready事件的写法
           */
          if (typeof selector === 'function') {
            this.elements.push(document)
            this.ready(selector)
          } else {
            var context = context || document;
            var isDocument = (ele) => Object.prototype.toString.call(ele) == '[object HTMLDocument]' || '[object Document]'
            if (isDocument(selector)) {
              this.elements.push(selector)
            } else {
              /**
               * 如果是字符串的话就查询该节点 $('.class') | $('#id')
               */
              if (context.querySelectorAll) {
                var arr = context.querySelectorAll(selector);
                for (var i = 0; i < arr.length; i++) {
                  this.elements.push(arr[i]);
                }
              }
            }
          }
        },
        //实现each
        each: function (callback) {
         
        },
        //实现ready
        ready: function (callback) {
          
        },
        //实现bind
        bind: function (type, callback) {
         
        }
      }
      /**
       * 让两个作用域不一样的对象共享一个方法,让他们的原型指向一致,即Init.prototype = _$.prototype
       * 那么原型一致之后 就可以共享this.elements 属性了。
       */
      _$.prototype.Init.prototype = _$.prototype;
      window.$ = _$;
    })(window || global);
    

    ready

    //实现ready
    ready: function (callback) {
      var isDocument = (ele) => Object.prototype.toString.call(ele) == '[object HTMLDocument]' || '[object Document]'
      //如果已经取得了节点
      if (isDocument(this.elements[0])) {   
        if (document.addEventListener) { //判断火狐、谷歌
          /**
           * DOM树构建完成的时候就会执行DOMContentLoaded
           * 页面上所有的DOM,样式表,脚本,图片,flash都已经加载完成了,才会触发window.onload
           * 这也就是$(document).ready() 比 window.onload 执行早的原因
           * 
           * arguments.callee 博客里面有一篇文章 [js-递归] 里面专门讲到了,这里不再解释了
           */
          document.addEventListener('DOMContentLoaded', function () {
            document.removeEventListener('DOMContentLoaded', arguments.callee, false)
            callback()
          }, false)
        } else if (document.attachEvent) { //判断IE
          document.attachEvent('onreadystatechange', function () {
            if (document.readyState == 'complete') {
              document.detachEvent('onreadystatechange', arguments.callee);
              callback()
            }
          })
        } else if (document.lastChild == document.body) { //body已经加载完了,就直接回调了
          callback()
        }
      }
    },
    

    each

    //实现each
     each: function (callback) {
        if (this.elements.length > 0) {
            for (var i = 0; i < this.elements.length; i++) {
            callback.call(this, this.elements[i], i);
            }
        }
     },
    

    bind

    //实现bind
    bind: function (type, callback) {
      if (document.addEventListener) { //判断火狐、谷歌
        this.each(function (item, i) {
            item.addEventListener(type, callback, false)
        })
        } else if (document.attachEvent) { //判断IE
        this.each(function (item, i) {
            item.attachEvent('on' + type, callback)
        })
        } else {
        this.each(function (item, i) { //其他浏览器 egg: item.onclick = function(){}
            item['on' + type] = callback
        })
      }
    }
    

    $.fn.extend/$.extend
    $.fn.extend是为查询的节点对象扩展方法,是基于$的原型扩展的方法

    $.extend是扩展常规方法,是$的静态方法。

    官方给出解释:

    jQuery.extend(): Merge the contents of two or more objects together into the first object.(把两个或者更多的对象合并到第一个当中);

    jQuery.fn.extend():Merge the contents of an object onto the jQuery prototype to provide new jQuery instance methods.(把对象挂载到jQuery的prototype属性,来扩展一个新的jQuery实例方法)

    $.fn.extend方法的初衷是我们扩展之后可以用$("").newMetod()这样访问,实际上就是给$原型加一个extend方法。这中间的fn其实类似于命名空间的作用,没什么实际的意义。为的是和 $.extend作区分

    $.fn.extend

    ; (function (win) {
      ...
      _$.prototype.Init.prototype = _$.prototype;
      
       _$.fn = _$.prototype; //把对象挂载到jQuery的prototype属性
    
      var isObj = (o) => Object.prototype.toString().call(o) === '[object Object]';
      $.fn.extend = function (obj) {
        if (isObj(obj)) {
          for (var i in obj) {
            this[i] = obj  //注意这里的this指向是 $.prototype
          }
        }
      }
    

    $.extend

    var isObj = (o) => Object.prototype.toString().call(o) === '[object Object]';
    ...
    _$.extend = function (obj) {
        if (isObj(obj)) {
            for (var i in obj) {
                this[i] = obj[i]; //注意这里的this指向是 $
            }
        }
    }
    

    这俩看上去一模一样啊,没啥区别,注释里面已经说了,this指向不同。咱们来看个例子:

    <!DOCTYPE html>
    <html>
    <head>
        <title>jQuery.extend()与jQuery.fn.extend()区别</title>
        <meta charset="utf-8">
        <script type="text/javascript" src="jquery.js"></script>
        <!-- 开始扩展 -->
        <script type="text/javascript">
            (function($){
                   $.extend({
                       sayHello:function(){
                           console.log("Hello");
                       }
                   });
                   $.fn.extend({
                       sayHello:function(){
                           console.log("Hello");
                       }
                   });
            })(jQuery);
        </script>
        <!-- 调用 -->
        <script type="text/javascript">
            $(document).ready(function(){
                //$.extend扩展调用
                $.sayHello();
    
                //$.fn.extend扩展调用
                $('#test').sayHello();
            })
        </script>
    </head>
    <body>
      <div id="test"></div>
    </body>
    </html>
    

    这样以来就看的很明白了。
    jQuery.extend(object); 为扩展jQuery类本身,为自身添加新的方法。$.xxx()

    jQuery.fn.extend(object);给jQuery对象添加方法 $('#test').xxx()

    $.extend常见用法

    //在jquery全局对象中扩展一个net命名空间。
    $.extend({net:{}}); 
    
    //方法扩展到之前扩展的Jquery的net命名空间中去。
    $.extend($.net,{
        sayHello:function(){ console.log("Hello"); } 
    })
    
    //extend方法还有一个重载原型
    //extend(boolean,dest,src1,src2,src3...),第一个参数boolean代表是否进行深度拷贝
    var a = { protocol: 'http', hash: { a: 1, b: 2 } }
    var b = { host: 'chuchur.com', hash: { b: 1, c: 2 } }
    
    var result = $.extend(true, {}, a, b)
    console.log(result)  //{ protocol: 'http',host: 'chuchur.com', hash: { a: 1, b: 1,c:2 } }
    
    var result = $.extend(false, {}, a, b)
    console.log(result)  //{ protocol: 'http',host: 'chuchur.com', hash: { b: 1, c:2 } } 
    
    

    完整代码

    ; (function (win) {
      var _$ = function (selector, context) {
        /**
         * 通常咱们定义一个 函数 var Fun = function(){}
         * 然后定义一个 Fun.prototype.init = function(){} 
         * 那么咱们调用init 的时候 得先要实例化对象 var f = new Fun()
         * 然后f.init()
         * 这里就省去了 var $ = new $()
         */
        return new _$.prototype.Init(selector, context);
      }
      _$.prototype = {
        //初始化$
        Init: function (selector, context) {
          this.elements = [];
          /**
           * 传入的类型是function 就执行ready事件,如果是document 就将document对象插入到this.elements
           * 主要就是判断$(document).ready  和 $(function(){}) 这两种的ready事件的写法
           */
          if (typeof selector === 'function') {
            this.elements.push(document)
            this.ready(selector)
          } else {
            var context = context || document;
            var isDocument = (ele) => Object.prototype.toString.call(ele) == '[object HTMLDocument]' || '[object Document]'
            if (isDocument(selector)) {
              this.elements.push(selector)
            } else {
              /**
               * 如果是字符串的话就查询该节点 $('.class') | $('#id')
               */
              if (context.querySelectorAll) {
                var arr = context.querySelectorAll(selector);
                for (var i = 0; i < arr.length; i++) {
                  this.elements.push(arr[i]);
                }
              }
            }
          }
        },
        //实现each
        each: function (callback) {
          if (this.elements.length > 0) {
            for (var i = 0; i < this.elements.length; i++) {
              callback.call(this, this.elements[i], i);
            }
          }
        },
        //实现ready
        ready: function (callback) {
          var isDocument = (ele) => Object.prototype.toString.call(ele) == '[object HTMLDocument]' || '[object Document]'
          //如果已经取得了节点
          if (isDocument(this.elements[0])) {
    
            if (document.addEventListener) { //判断火狐、谷歌
              /**
               * DOM树构建完成的时候就会执行DOMContentLoaded
               * 页面上所有的DOM,样式表,脚本,图片,flash都已经加载完成了,才会触发window.onload
               * 这也就是$(document).ready() 比 window.onload 执行早的原因
               * 
               * arguments.callee 博客里面有一篇文章 js-递归里面专门讲到了,这里不再解释了
               */
              document.addEventListener('DOMContentLoaded', function () {
                document.removeEventListener('DOMContentLoaded', arguments.callee, false)
                callback()
              }, false)
            } else if (document.attachEvent) { //判断IE
              document.attachEvent('onreadystatechange', function () {
                if (document.readyState == 'complete') {
                  document.detachEvent('onreadystatechange', arguments.callee);
                  callback()
                }
              })
            } else if (document.lastChild == document.body) { //body已经加载完了,就直接回调了
              callback()
            }
          }
        },
        //实现bind
        bind: function (type, callback) {
          if (document.addEventListener) { //判断火狐、谷歌
            this.each(function (item, i) {
              item.addEventListener(type, callback, false)
            })
          } else if (document.attachEvent) { //判断IE
            this.each(function (item, i) {
              item.attachEvent('on' + type, callback)
            })
          } else {
            this.each(function (item, i) { //其他浏览器 egg: item.onclick = function(){}
              item['on' + type] = callback
            })
          }
        }
      }
      /**
       * 让两个作用于不一样的对象共享一个方法,让他们的原型指向一直,即Init.prototype = _$.prototype
       * 那么指向之后 就可以共享this.elements 属性了。
       */
      _$.prototype.Init.prototype = _$.prototype;
      
      var isObj = (o) => Object.prototype.toString().call(o) === '[object Object]';
      $.fn.extend = function (obj) {
        if (isObj(obj)) {
          for (var i in obj) {
            this[i] = obj //注意这里的this指向是 $.prototype
          }
        }
        //....这里是简写
      }
    
      _$.extend = function (obj) {
        if (isObj(obj)) {
          for (var i in obj) {
            this[i] = obj[i]; //注意这里的this指向是 $
          }
        }
        //....这里是简写
      }
    
      window.$ = _$;
    })(window || global);
    

    【完】

  • 相关阅读:
    multiprocessing 多进程实现 生产者与消费者模型JoinableQueue
    条件锁condition与Queue()
    threading 官方 线程对象和锁对象以及条件对象condition
    【NOIp训练】—子串查找VII(AC自动机+树链剖分+线段树)
    【NOIp训练】—子串查找VII(AC自动机+树链剖分+线段树)
    【HDU 5628】—Clarke and math(狄利克雷卷积快速幂)
    【HDU 5628】—Clarke and math(狄利克雷卷积快速幂)
    【NOIp2019模拟】题解
    【NOIp2019模拟】题解
    【NOIp2019模拟】题解
  • 原文地址:https://www.cnblogs.com/chuchur/p/10462304.html
Copyright © 2011-2022 走看看