亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

jQuery.extend()的實現方式詳解及實例

2019-11-20 22:35:47
字體:
來源:轉載
供稿:網友

復制代碼 代碼如下:

<script type="text/javascript" src="jquery-1.5.2.js"></script>
<script>
obj1 = { a : 'a', b : 'b' };
obj2 = {  x : { xxx : 'xxx', yyy : 'yyy' },  y : 'y' };

$.extend(true, obj1, obj2);

alert(obj1.x.xxx);  // 得到"xxx"

obj2.x.xxx = 'zzz';
alert(obj2.x.xxx);  // 得到"zzz"
alert(obj1.x.xxx);  // 得帶"xxx"
</script>


$.extend(true, obj1, obj2)表示以obj2中的屬性擴展對象obj1,第一個參數設為true表示深復制。
雖然obj1中原來沒有"x"屬性,但經過擴展后,obj1不但具有了"x"屬性,而且對obj2中的"x"屬性的修改也不會影響到obj1中"x"屬性的值,這就是所謂的“深復制”了。

淺復制的實現

如果僅僅需要實現淺復制,可以采用類似下面的寫法:

復制代碼 代碼如下:

$ = {
     extend : function(target, options) {
        for (name in options) {
            target[name] = options[name];
        }
        return target;
    }
};

也就是簡單地將options中的屬性復制到target中。我們仍然可以用類似的代碼進行測試,但得到的結果有所不同(假設我們的js命名為“jquery-extend.js”):
復制代碼 代碼如下:

<script type="text/javascript" src="jquery-extend.js"></script>
<script>
obj1 = { a : 'a', b : 'b' };
obj2 = {  x : { xxx : 'xxx', yyy : 'yyy' },  y : 'y' };
$.extend(obj1, obj2);
alert(obj1.x.xxx);  // 得到"xxx"
obj2.x.xxx = 'zzz';
alert(obj2.x.xxx);  // 得到"zzz"
alert(obj1.x.xxx);  // 得帶"zzz"
</script>

obj1中具有了"x"屬性,但這個屬性是一個對象,對obj2中的"x"的修改也會影響到obj1,這可能會帶來難以發現的錯誤。

深復制的實現

如果我們希望實現“深復制”,當所復制的對象是數組或者對象時,就應該遞歸調用extend。如下代碼是“深復制”的簡單實現:

復制代碼 代碼如下:

$ = {
 extend : function(deep, target, options) {
  for (name in options) {
   copy = options[name];
   if (deep && copy instanceof Array) {
                target[name] = $.extend(deep, [], copy);
            } else if (deep && copy instanceof Object) {
                target[name] = $.extend(deep, {}, copy);
   } else {
    target[name] = options[name];
   }
  }
  return target;
 }
};

具體分為三種情況:
1. 屬性是數組時,則將target[name]初始化為空數組,然后遞歸調用extend;
2. 屬性是對象時,則將target[name]初始化為空對象,然后遞歸調用extend;
3. 否則,直接復制屬性。

測試代碼如下:

復制代碼 代碼如下:

<script type="text/javascript" src="jquery-extend.js"></script>
<script>
obj1 = { a : 'a', b : 'b' };
obj2 = {  x : { xxx : 'xxx', yyy : 'yyy' },  y : 'y' };
$.extend(true, obj1, obj2);
alert(obj1.x.xxx);  // 得到"xxx"
obj2.x.xxx = 'zzz';
alert(obj2.x.xxx); // 得到"zzz"
alert(obj1.x.xxx); // 得到"xxx"
</script>

現在如果指定為深復制的話,對obj2的修改將不會對obj1產生影響了;不過這個代碼還存在一些問題,比如“instanceof Array”在IE5中可能存在不兼容的情況。jQuery中的實現實際上會更復雜一些。

更完整的實現

下面的實現與jQuery中的extend()會更接近一些:

復制代碼 代碼如下:

$ = function() {
    var copyIsArray,
        toString = Object.prototype.toString,
        hasOwn = Object.prototype.hasOwnProperty;

    class2type = {
        '[object Boolean]' : 'boolean',
        '[object Number]' : 'number',
        '[object String]' : 'string',
        '[object Function]' : 'function',
        '[object Array]' : 'array',
        '[object Date]' : 'date',
        '[object RegExp]' : 'regExp',
        '[object Object]' : 'object'
    },

    type = function(obj) {
        return obj == null ? String(obj) : class2type[toString.call(obj)] || "object";
    },

    isWindow = function(obj) {
        return obj && typeof obj === "object" && "setInterval" in obj;
    },

    isArray = Array.isArray || function(obj) {
        return type(obj) === "array";
    },

    isPlainObject = function(obj) {
        if (!obj || type(obj) !== "object" || obj.nodeType || isWindow(obj)) {
            return false;
        }

        if (obj.constructor && !hasOwn.call(obj, "constructor")
                && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
            return false;
        }

        var key;
        for (key in obj) {
        }

        return key === undefined || hasOwn.call(obj, key);
    },

    extend = function(deep, target, options) {
        for (name in options) {
            src = target[name];
            copy = options[name];

            if (target === copy) { continue; }

            if (deep && copy
                    && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {
                if (copyIsArray) {
                    copyIsArray = false;
                    clone = src && isArray(src) ? src : [];

                } else {
                    clone = src && isPlainObject(src) ? src : {};
                }

                target[name] = extend(deep, clone, copy);
            } else if (copy !== undefined) {
                target[name] = copy;
            }
        }

        return target;
    };

    return { extend : extend };
}();


首先是 $ =  function(){...}();這種寫法,可以理解為與下面的寫法類似:
復制代碼 代碼如下:

func = function(){...};
$ =  func();

也就是立即執行函數,并將結果賦給$。這種寫法可以利用function來管理作用域,避免局部變量或局部函數影響全局域。另外,我們只希望使用者調用$.extend(),而將內部實現的函數隱藏,因此最終返回的對象中只包含extend:
復制代碼 代碼如下:

return { extend : extend };

接下來,我們看看extend函數與之前的區別,首先是多了這句話:
復制代碼 代碼如下:

if (target === copy) { continue; }

這是為了避免無限循環,要復制的屬性copy與target相同的話,也就是將“自己”復制為“自己的屬性”,可能導致不可預料的循環。

然后是判斷對象是否為數組的方式:

復制代碼 代碼如下:

   type = function(obj) {
        return obj == null ? String(obj) : class2type[toString.call(obj)] || "object";
   },
   isArray = Array.isArray || function(obj) {
        return type(obj) === "array";
    }

如果瀏覽器有內置的Array.isArray 實現,就使用瀏覽器自身的實現方式,否則將對象轉為String,看是否為"[object Array]"。

最后逐句地看看isPlainObject的實現:

復制代碼 代碼如下:

if (!obj || type(obj) !== "object" || obj.nodeType || isWindow(obj)) {
    return false;
}

如果定義了obj.nodeType,表示這是一個DOM元素;這句代碼表示以下四種情況不進行深復制:
1. 對象為undefined;
2. 轉為String時不是"[object Object]";
3. obj是一個DOM元素;
4. obj是window。
之所以不對DOM元素和window進行深復制,可能是因為它們包含的屬性太多了;尤其是window對象,所有在全局域聲明的變量都會是其屬性,更不用說內置的屬性了。

接下來是與構造函數相關的測試:

復制代碼 代碼如下:

  if (obj.constructor && !hasOwn.call(obj, "constructor")
                && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
        return false;
    }

如果對象具有構造函數,但卻不是自身的屬性,說明這個構造函數是通過prototye繼承來的,這種情況也不進行深復制。這一點可以結合下面的代碼結合進行理解:
復制代碼 代碼如下:

        var key;
        for (key in obj) {
        }
        return key === undefined || hasOwn.call(obj, key);

這幾句代碼是用于檢查對象的屬性是否都是自身的,因為遍歷對象屬性時,會先從自身的屬性開始遍歷,所以只需要檢查最后的屬性是否是自身的就可以了。
這說明如果對象是通過prototype方式繼承了構造函數或者屬性,則不對該對象進行深復制;這可能也是考慮到這類對象可能比較復雜,為了避免引入不確定的因素或者為復制大量屬性而花費大量時間而進行的處理,從函數名也可以看出來,進行深復制的只有"PlainObject"。
如果我們用如下代碼進行測試:
復制代碼 代碼如下:

<script type="text/javascript" src="jquery-1.5.2.js"></script>
<script>
function O() {
 this.yyy = 'yyy';
}

function X() {
 this.xxx = 'xxx';
}

X.prototype = new O();

x = new X();

obj1 = { a : 'a', b : 'b' };
obj2 = { x : x };
$.extend(true, obj1, obj2);

alert(obj1.x.yyy);  // 得到"xxx"
obj2.x.yyy = 'zzz';
alert(obj1.x.yyy);  // 得到"zzz"
</script>


可以看到,這種情況是不進行深復制的。
總之,jQuery中的extend()的實現方式,考慮了兼容瀏覽器的兼容,避免性能過低,和避免引入不可預料的錯誤等因素。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩中文字幕视频| 亚洲欧美在线磁力| 国语自产精品视频在线看| 日韩在线免费视频| 精品成人乱色一区二区| 九九热精品视频在线播放| 在线激情影院一区| 精品国产乱码久久久久久虫虫漫画| 欧美亚洲另类制服自拍| 色婷婷综合成人av| 亚洲色图35p| 国产精品美腿一区在线看| 成人中文字幕在线观看| 国产精品网址在线| 在线观看精品自拍私拍| 成人伊人精品色xxxx视频| 欧美性猛交xxxx富婆| 日日摸夜夜添一区| 一本色道久久综合狠狠躁篇的优点| 国产成人涩涩涩视频在线观看| 欧美大尺度在线观看| 欧美国产日韩xxxxx| 国产99久久精品一区二区永久免费| 亚洲欧美日本另类| 亚洲国产精品免费| 日韩有码在线观看| 91精品国产色综合久久不卡98口| 黑人狂躁日本妞一区二区三区| 欧美午夜影院在线视频| 欧美亚洲视频一区二区| 色哟哟网站入口亚洲精品| 国产一区二区久久精品| 亚洲a∨日韩av高清在线观看| 亚洲最新av网址| 国产精品综合不卡av| 亚洲精品日韩在线| 91丝袜美腿美女视频网站| 97国产在线观看| 久久久亚洲精品视频| 一区二区三区天堂av| 国产精品一区二区三区久久久| 国产成人av在线播放| 国产欧美va欧美va香蕉在线| 久久精品中文字幕电影| 九九热这里只有精品免费看| 92版电视剧仙鹤神针在线观看| 国产亚洲人成网站在线观看| 亚洲精品av在线播放| 久久人人爽国产| 亚洲色图15p| 成人激情在线播放| 97av在线视频免费播放| 国产精品视频区1| 久久精品视频亚洲| 午夜精品国产精品大乳美女| 成人免费视频a| 欧美一区二区三区四区在线| 欧美性xxxx极品hd欧美风情| 久久影视电视剧免费网站清宫辞电视| 国产精品国产自产拍高清av水多| 成人网址在线观看| 日本久久精品视频| 久久在线精品视频| 亚洲一区二区久久| 日韩av资源在线播放| 一区二区欧美久久| 在线亚洲午夜片av大片| 日韩av在线影院| 日本中文字幕成人| 欧美日韩另类在线| 91精品国产综合久久香蕉| 亚洲tv在线观看| 国产视频精品自拍| 中文字幕亚洲欧美日韩高清| 91在线观看免费观看| 少妇av一区二区三区| 日韩电影网在线| 色视频www在线播放国产成人| 欧美在线性视频| 欧美专区在线播放| 最近更新的2019中文字幕| 国产精品午夜视频| 国产成人精品综合久久久| 狠狠色噜噜狠狠狠狠97| 欧美一级大片在线观看| 亚洲成人av在线| 久久成人精品视频| 亚洲国产欧美一区二区三区同亚洲| 亚洲男人天堂久| 国产亚洲欧洲高清| 国语自产偷拍精品视频偷| 日韩av电影免费观看高清| 欧美大胆a视频| 日韩精品免费观看| 欧美午夜www高清视频| 欧美夫妻性视频| 久久精品国产69国产精品亚洲| 欧美另类第一页| 欧美亚洲第一页| 77777少妇光屁股久久一区| 成人情趣片在线观看免费| 亚洲人成电影在线播放| 久久电影一区二区| 国产欧美va欧美va香蕉在线| 日本人成精品视频在线| 成人福利网站在线观看| 亚洲精品福利免费在线观看| 久久久国产精品视频| 久久影院在线观看| 国产精品欧美一区二区三区奶水| 91高清免费视频| 91亚洲国产成人久久精品网站| 日韩欧美国产网站| 久久久久久久久亚洲| 色综合久久久久久中文网| 国产精品中文字幕在线观看| 久久九九免费视频| 国产精品久久久久免费a∨| 亚洲片在线观看| 成人福利视频在线观看| 欧美日韩在线视频首页| 亚洲欧美日韩国产中文专区| 久久影视免费观看| 亚洲区在线播放| 91老司机精品视频| 久久99精品久久久久久噜噜| 亚洲男女性事视频| 日韩欧亚中文在线| 国产精品高清在线观看| 九九热最新视频//这里只有精品| 欧美综合激情网| 米奇精品一区二区三区在线观看| 亚洲精品国产成人| 国产精品久久久久7777婷婷| 久久久999国产精品| 日韩av在线高清| 一色桃子一区二区| 亚洲免费av网址| 欧美国产日韩视频| 成人性生交xxxxx网站| 在线日韩精品视频| 久久视频在线直播| 欧美一区二区色| 国产精品中文在线| 亚洲社区在线观看| 久久精品国亚洲| 久久久久久久国产| 九九热视频这里只有精品| 国产成人精品日本亚洲专区61| 日韩精品视频观看| 久久av资源网站| 亚洲成人黄色网| 中文字幕视频在线免费欧美日韩综合在线看| 欧美午夜电影在线| 成人乱人伦精品视频在线观看| 91精品视频免费看| 国产精品久久9| 中文字幕国产精品久久| 欧洲亚洲女同hd| 久久久久久这里只有精品| 亚洲天堂av综合网| 性欧美视频videos6一9| 亚洲第一页中文字幕| 91在线高清免费观看|