jQuery源碼二之extend的實現

extend是jQuery中一個比較核心的代碼,若是有查看jQuery的源碼的話,就會發現jQuery在多處調用了extend方法。jquery

做用

  1. 對任意對象進行擴展
  2. 擴展某個實例對象
  3. 對jquery自己的實例方法進行擴展

實現

基礎版本, 對簡單對象進行擴展
jQuery.prototype.extend = jQuery.extend = function(){
     var target = arguments[0] || {}; //獲取第一個參數做爲目標結果
     var i = 1; //設置開始擴展的下標,擴展時第一個參數不會進行改變,不須要遍歷
     var length = arguments.length;
     var option;
     if(typeof target !== 'object') {
       target = {};
     }
     
     for(; i< length; i++){
       option = arguments[i]
       for(var name in option){
         target[name] = option[name]
       }
     }
     return target
   }
   
   //調用
   var i = {a: 0};
   var b = {c: 9};
   console.log($().extend(i,b)) // {a:0, c:9}
升級版本1.0, 對複雜對象進行擴展。

在上面,咱們已經寫出的extend的基礎版本,可是若是咱們簡單測試一下,就會發現還是有問題存在的。
咱們可使用上面的方法,對下面的對象進行擴展函數

var n = {
        al: 90,
        m: {
          d: 23,
        }
      }
      var b = {m:{
        c: 98
      }};
      console.log($().extend(n,b)) // {al: 90, m: { c: 98 }}

簡單的從結果來看,返回的結果並不符合咱們的預期,基礎版本的方法彷佛只是簡單的值替換而已。那麼來簡單升級一下代碼吧。
在升級代碼以前,須要瞭解一下關於淺拷貝和深拷貝的相關。測試

關於淺拷貝和深拷貝的那些事
  1. 淺拷貝,
    對於淺拷貝,個人簡單理解就是: 淺拷貝就是對最表面的層級進行拷貝,若是某一被拷貝對象的值發生了改變,最終的拷貝結果也會隨之發生改變。
var i = {a: 0};
      var b = {c: 9};
      console.log($().extend(i,b)) // {a: 90, c:9}
      i.a = 90
  1. 深拷貝,深拷貝主要的是面對複雜對象,若是淺拷貝是對最表面的一層進行拷貝,那麼深拷貝就是,對拷貝對象的每個層級都進行拷貝,某種層面來講,勉強算得上是遞歸的淺拷貝吧,可是比較不一樣的是,深拷貝中,若是某一個被拷貝對象的值發生了改變,拷貝結果是不會隨之發生變化的,是一個獨立的存儲空間。
var n = {
     al: 90,
     m: {
       d: 23,
     }
   }
   var b = {m:{
     c: 98
   }};
   console.log($().extend(true,{},n,b))
   console.log(n)
   n.al = "cs"

結果:
Image textthis

深拷貝extend代碼擴展

jQuery.extend是提供深拷貝的,須要將第一參數傳爲true。
基本思路:prototype

  1. 首先先對第一個傳入參數進行判斷,判斷是不是boolean類型,來決定是否須要進行深拷貝;
var deep = false;
   if (typeof target === 'boolean') {
     deep = target;
     target = arguments[1];
     i = 2;  //由於第一參數爲boolean,因此拷貝對象從argument[1]開始,但一般第一個拷貝對象是不須要比遍歷的,因此遍歷下標從2開始。
   }
  1. 對須要遍歷的對象進行判斷,判斷是不是複雜類型。使用extend對jquery進行擴展。
if (length === i) { //此時extend參數只有一個,可是目標應該是this,因此獲取到this;
     target = this;  //但同時 i = 1;沒法進行遍歷,因此將遍歷下標後退一位
     i--;
   }
   
   jQuery.extend({
     isArray: function(obj) {
       return toString.call(obj) === '[object Array]';
     },
     isPainObj: function(obj) {
       return toString.call(obj) === '[object Object]';
     }
   })
  1. extend方法改造。
jQuery.prototype.extend = jQuery.extend = function(){
     var target = arguments[0] || {};
     var i = 1;
     var length = arguments.length;
     var option, copy, src, copyisArray, clone;
     for(; i< length; i++){
       if((option = arguments[i]) != null ){
         for(name in option) {
           src = target[name];
           copy = option[name];
           if(jQuery.isPainObj(copy) || (copyisArray = jQuery.isArray(copy))) {
             if(copyisArray) {
               copyisArray = false;
               clone = src && jQuery.isArray(src) ? src : [];
             } else {
               clone = src && jQuery.isPainObj(src) ? src : {};
             }
             target[name] = jQuery.extend(clone,copy)
           } else if(copy !== undefined) {
             target[name] = copy
           }
         }
       }
     }
     return target
   }

行了,到這裏爲止,咱們就已經完成了簡單的extend函數了,其實比較重要的是深拷貝和淺拷貝,關於這一點,下次再記錄吧。code

相關文章
相關標籤/搜索