<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      從零開始,DIY一個jQuery(1)

      從本篇開始會陪大家一起從零開始走一遍 jQuery 的奇妙旅途,在整個系列的實(shí)踐中,我們會把 jQuery 的主要功能模塊都了解和實(shí)現(xiàn)一遍。

      這會是一段很長的歷程,但也會很有意思 —— 作為前端領(lǐng)域的經(jīng)典之作,jQuery 里有著太多奇思妙想,如果能夠深入理解它,對于我們穩(wěn)固js基礎(chǔ)、提升前端大法技能來說大有裨益。

      另外,本系列的相關(guān)代碼均可以從 我的github 上獲取到。

      1. 免 new 實(shí)現(xiàn)

      我們在使用很多插件的時候,都需要使用 new XXX() 的寫法來實(shí)例化一個引用:

      var list = new Slip(document.getElementById('slip'), {
        //options
      });

      jQuery 同樣作為一個面向?qū)ο蟮墓ぞ邘欤谖覀儎?chuàng)建一個實(shí)例時卻無需使用 new 語法,節(jié)省了一些代碼量:

      var $div = $('div');
      //不需要如下寫法:
      //var $div = new $('div');

      這種便捷的形式依賴了工廠模式,其實(shí)現(xiàn)非常簡單,把 new 封裝在庫內(nèi)即可,讓每次調(diào)用 jQuery() 時自行在內(nèi)部進(jìn)行一次實(shí)例化:

      (function() {
          var _jQuery = window.jQuery,
              _$ = window.$;
      
          var version = "0.0.1",
              jQuery = function(selector) {
                  console.log(document.querySelector(selector))
              };
      
          jQuery.prototype = {
              jquery: version,
              constructor: jQuery
          };
      
          window.$ = window.jQuery = function(selector) {
              return new jQuery(selector);  //notice here~
          };
      })();

      留意這里我們走的 IIFE 形式,讓 jQuery 代碼庫形成自己的作用域,避免污染外部變量。

      于是乎以上就是咱寫的第一個 JQ 雛形,簡單跑一下:

      <div></div>
      <script>
          var $div = $('div');  //<div></div>
          console.log($div.jquery);  //0.0.1
      </script>

      別忘了后續(xù)我們還希望能通過 $.extend / $.fn.extend 來擴(kuò)展 JQ 的靜態(tài)方法和原型方法,我們把出口方法抽出來增加這個 extend 的API:

          function Factory(selector){  //抽出構(gòu)造函數(shù)
              return new jQuery(selector);
          }
      
          Factory.fn = jQuery.prototype;
      
          Factory.extend = Factory.fn.extend = function(){
              console.log(this)
          };
      
          window.$ = window.jQuery = Factory;

      這樣我們也能直接通過 $.fn.jquery 來獲取當(dāng)前 JQ 版本號了。

      如果希望可以通過 $.prototype 直接訪問 jQuery 的原型對象,再修改下這句代碼即可:

      Factory.prototype = Factory.fn = jQuery.prototype;

      2. 寫法優(yōu)化

      事實(shí)上我們不太喜歡再寫多一個冗余的 Factory 構(gòu)造函數(shù)來作為 window.jQuery 的引用,也不喜歡(在模塊內(nèi)部)使用 Factory.extend() 來擴(kuò)展 JQ,它聽起來和 JQ 沒有半毛錢關(guān)系。

      如果可以,直接把 jQuery 方法作為接口輸出,且在模塊內(nèi)部能以 jQuery.extend()  的形式來調(diào)用擴(kuò)展接口,這樣的形式更佳。

      也就是說我們希望代碼應(yīng)該是這樣寫的:

          jQuery.extend = jQuery.fn.extend = function(){
              console.log(this)
          };
          window.jQuery = window.$ = jQuery;

      “直接把 jQuery 方法作為接口輸出”意味著我們要把工廠模式挪入 jQuery 方法中,顯然我們不能這樣改:

          var version = "0.0.1",
              jQuery = function (selector) {
                  return new jQuery(selector);
              };

      這樣死循環(huán)了,調(diào)用棧會直接爆掉~

      于是我們可以抽出一個 init 方法來做初始化處理(比如簡單地注入檢索到的元素到JQ對象中),把 jQuery 方法中的內(nèi)容更改為 return new init(selector) 就行了。

      保證兩個前提:

      1. this 指向 jQuery 上下文
      
      2. 其原型指向 jQuery 的原型

      第一點(diǎn)很好理解,方便我們直接在 init 方法中通過對 this 的操作來處理 JQ 實(shí)例上下文,如:

        //注入元素到 JQ 實(shí)例對象中
        this[0] = elem;
        this.length = 1;

      針對這點(diǎn),我們不妨把 init 作為 jQuery.prototype 的屬性方法來實(shí)現(xiàn):

          var version = "0.0.1",
              jQuery = function(selector) {
                  return new jQuery.fn.init()  //修改點(diǎn)1
              };
      
          //方便我們使用 jQuery.fn 來引用 jQuery 原型對象
          jQuery.fn = jQuery.prototype = {
              jquery: version,
              constructor: jQuery
          };
      
           //修改點(diǎn)2 —— init 作為原型方法,確保 this 指向正確
          jQuery.fn.init = function( selector ) {
              if ( !selector ) {
                  return;
              } else {
                  var elem = document.querySelector( selector );
                  if ( elem ) {
                      this[0] = elem;
                      this.length = 1;
                  }
              }
          };
      
          jQuery.extend = jQuery.fn.extend = function(){
              console.log(this)
          };
      
          window.$ = window.jQuery = jQuery;

      然而這時候存在一個問題 —— JQ實(shí)例對象無法訪問原型屬性/方法:

          var $div = $('div');
          console.log($div.jquery);  //undefined

      原因很簡單——我們還未實(shí)現(xiàn)上述提及的第二個前提——“init 原型指向 jQuery 的原型”

      在 js 中,實(shí)例的內(nèi)部原型(__proto__)總是指向其構(gòu)造函數(shù)的原型(prototype),而經(jīng)過我們這番修改,JQ實(shí)例的構(gòu)造函數(shù)已經(jīng)變成了 jQuery.fn.init ,而其原型并非指向 jQuery 的原型,這導(dǎo)致 JQ 實(shí)例無法順其原型鏈爬取到 jQuery.prototype。

      要實(shí)現(xiàn)這個條件,只需要做小小改動——把 jQuery.fn.init 的原型指向 jQuery 的原型(jQuery.prototype / jQuery.fn)即可:

          var init = jQuery.fn.init = function( selector ) {
              if ( !selector ) {
                  return;
              } else {
                  var elem = document.querySelector( selector );
                  if ( elem ) {
                      this[0] = elem;
                      this.length = 1;
                  }
              }
          };
      
          init.prototype = jQuery.fn;  //修改點(diǎn)

      這里貼下完整代碼:

          var version = "0.0.1",
              jQuery = function(selector) {
                  return new jQuery.fn.init(selector)
              };
      
          jQuery.fn = jQuery.prototype = {
              jquery: version,
              constructor: jQuery
          };
      
          var init = jQuery.fn.init = function( selector, context, root ) {
              if ( !selector ) {
                  return;
              } else {
                  var elem = document.querySelector( selector );
                  if ( elem ) {
                      this[0] = elem;
                      this.length = 1;
                  }
              }
          };
      
          init.prototype = jQuery.fn;
      
          jQuery.extend = jQuery.fn.extend = function(){
              console.log(this)
          };
      
          window.$ = window.jQuery = jQuery;
      View Code

      3. 鏈?zhǔn)綄懛▽?shí)現(xiàn)

      JQ 里一個很大的亮點(diǎn)是,它支持鏈?zhǔn)綄懛ǎ{(diào)用起來非常方便:

      $('div').removeClass('hide').css('width', '100px')

      其實(shí)現(xiàn)其實(shí)非常簡單 —— 確保每個調(diào)用的方法尾部均返回自身即可,這里我們新增兩個實(shí)例方法做示例:

          jQuery.fn = jQuery.prototype = {
              jquery: version,
              constructor: jQuery,
              setBackground: function(){
                  this[0].style.background = 'yellow';
                  return this  //返回自身引用
              },
              setColor: function(){
                  this[0].style.color = 'blue';
                  return this  //返回自身引用
              }
          };
      
          var init = jQuery.fn.init = function( selector ) {
              if ( !selector ) {
                  return this; 
              } else {
                  var elem = document.querySelector( selector );
                  if ( elem ) {
                      this[0] = elem;
                      this.length = 1;
                  }
                  return this;
              }
          };

      鏈?zhǔn)秸{(diào)用:

      <div>hello world</div>
      
      <script>
          var $div = $('div');
          $div.setBackground().setColor();
      </script>

      效果如下,杠杠的:

      4. 沖突處理

      存在某些情況,用戶可能并不想拿 window.$ 甚至 window.jQuery 來引用 JQ 接口,或者已經(jīng)有其它庫使用了 window.$ 這個變量,如果我們粗暴地改變其引用肯定是不合理的。

      so 我們來實(shí)現(xiàn) JQ 中沖突處理的靜態(tài)接口 jQuery.noConflict,這意味著在代碼段開始時,就得先保存下當(dāng)前 window.$ 和 window.jQuery 兩個變量:

      (function(){
          var _jQuery = window.jQuery,
              _$ = window.$;
      
          //var version = "0.0.1"......
      })()

      然后是實(shí)現(xiàn) noConflict 方法,退耕還林,把保存的變量吐回去即可:

      (function(){
          var _jQuery = window.jQuery,
              _$ = window.$;
      
          //var version = "0.0.1"......
      
          jQuery.noConflict = function( deep ) {
              //確保window.$沒有再次被改寫
              if ( window.$ === jQuery ) {
                  window.$ = _$;
              }
      
              //確保window.jQuery沒有再次被改寫
              if ( deep && window.jQuery === jQuery ) {
                  window.jQuery = _jQuery;
              }
      
              return jQuery;  //返回 jQuery 接口引用
          };
      
          window.jQuery = window.$ = jQuery;
      })();

      deep 參數(shù)類型為 Boolean,若為真,表示要求連window.jQuery 變量都需要吐回去。

      留意在尾部我們返回了 jQuery 的接口引用,這意味著我們可以以

      var $$$ = jQuery.noConflict()

      的形式來把它賦予新的變量。

      接著在外部運(yùn)行如下代碼:

      <head>
          <meta charset="UTF-8">
          <title>DIY A JQ</title>
          <script>
              $ = 'old $';
              jQuery = 'old JQ'
          </script>
          <script src="jQuery.js"></script>
      </head>
      <body>
      
      <div>hello world</div>
      
      <script>
          var $div = $('div');
          $div.setBackground().setColor();
      
          var $$$ = $.noConflict(true);
          console.log($); 
          console.log(jQuery); 
          console.log($$$); 
      </script>

      輸出如下:

       

      第一篇就寫到這里,相關(guān)的代碼可以從 我的github 上下載到。

      下次我們會試著實(shí)現(xiàn)模塊化的寫法,并與時俱進(jìn),改用 ES6解構(gòu)賦值語法 + Rollup 來進(jìn)行打包以減少可能存在的冗余代碼段。

      共勉~

      posted @ 2016-07-31 02:47  vajoy  閱讀(7079)  評論(19)    收藏  舉報
      Copyright © 2014 - 2022 VaJoy Studio
      主站蜘蛛池模板: 久久夜色精品国产亚洲av| 国产午夜福利高清在线观看| 黄平县| 久久精品夜夜夜夜夜久久| 榆树市| 久久爱在线视频在线观看| 噜噜噜噜私人影院| 国产精品国三级国产av| 成人国产精品中文字幕| 无码中文av波多野结衣一区| 国产精品一码在线播放| 久久99精品久久久久久青青| 一本色道久久加勒比综合 | 亚洲午夜成人精品电影在线观看| 日韩乱码人妻无码中文字幕视频 | 老熟妇老熟女老女人天堂| 最新亚洲人成网站在线观看| 久久国产精品伊人青青草| 在线视频中文字幕二区| 美日韩在线视频一区二区三区| 亚洲男人电影天堂无码| 国产福利免费在线观看| 日韩精品一区二区蜜臀av| 国产成人精品无码免费看夜聊软件| 久热色视频精品在线观看| 蛟河市| 欧美成人精品三级在线观看| 午夜国产小视频| 4399理论片午午伦夜理片| 色色97| 国产精品永久在线观看| 日韩av天堂综合网久久| 无码AV无码免费一区二区| 亚洲人成影院在线观看| 九九热在线精品免费视频| 少妇真人直播免费视频| 成人av天堂男人资源站| 国模雨珍浓密毛大尺度150p| 丰满少妇被猛烈进出69影院| 免费人成在线观看网站| 亚洲国产日韩精品久久|