熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> JSP教程 >> 正文

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

2013-11-15 11:58:26  來源: JSP教程 
extend()函數是jQuery的基礎函數之一作用是擴展現有的對象   復制代碼 代碼如下:
<script type="text/javascript" src="jqueryjs"></script>
<script>
obj = { a : a b : b };
obj = { x : { xxx : xxx yyy : yyy } y : y };

  $extend(true obj obj);

  alert(objxxxx); // 得到"xxx"

  objxxxx = zzz;
alert(objxxxx); // 得到"zzz"
alert(objxxxx); // 得帶"xxx"
</script>

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

  淺復制的實現

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

復制代碼 代碼如下:
$ = {
extend : function(target options) {
for (name in options) {
target[name] = options[name];
}
return target;
}
};

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

復制代碼 代碼如下:
<script type="text/javascript" src="jqueryextendjs"></script>
<script>
obj = { a : a b : b };
obj = { x : { xxx : xxx yyy : yyy } y : y };
$extend(obj obj);
alert(objxxxx); // 得到"xxx"
objxxxx = zzz;
alert(objxxxx); // 得到"zzz"
alert(objxxxx); // 得帶"zzz"
</script>

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

  深復制的實現

  如果我們希望實現“深復制”當所復制的對象是數組或者對象時就應該遞歸調用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;
}
};

  
具體分為三種情況
屬性是數組時則將target[name]初始化為空數組然後遞歸調用extend
屬性是對象時則將target[name]初始化為空對象然後遞歸調用extend
否則直接復制屬性

  測試代碼如下

復制代碼 代碼如下:
<script type="text/javascript" src="jqueryextendjs"></script>
<script>
obj = { a : a b : b };
obj = { x : { xxx : xxx yyy : yyy } y : y };
$extend(true obj obj);
alert(objxxxx); // 得到"xxx"
objxxxx = zzz;
alert(objxxxx); // 得到"zzz"
alert(objxxxx); // 得到"xxx"
</script>

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

  更完整的實現

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

復制代碼 代碼如下:
$ = function() {
var copyIsArray
toString = ObjectprototypetoString
hasOwn = ObjectprototypehasOwnProperty;

  classtype = {
[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) : classtype[toStringcall(obj)] || "object";
}

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

  isArray = ArrayisArray || function(obj) {
return type(obj) === "array";
}

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

  if (objconstructor && !hasOwncall(obj "constructor")
&& !hasOwncall(objconstructorprototype "isPrototypeOf")) {
return false;
}

  var key;
for (key in obj) {
}

  return key === undefined || hasOwncall(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) : classtype[toStringcall(obj)] || "object";
}
isArray = ArrayisArray || function(obj) {
return type(obj) === "array";
}

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

  最後逐句地看看isPlainObject的實現

復制代碼 代碼如下:
if (!obj || type(obj) !== "object" || objnodeType || isWindow(obj)) {
return false;
}

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

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

復制代碼 代碼如下:
if (objconstructor && !hasOwncall(obj "constructor")
&& !hasOwncall(objconstructorprototype "isPrototypeOf")) {
return false;
}

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

復制代碼 代碼如下:
var key;
for (key in obj) {
}
return key === undefined || hasOwncall(obj key);

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

復制代碼 代碼如下:
<script type="text/javascript" src="jqueryjs"></script>
<script>
function O() {
thisyyy = yyy;
}

  function X() {
thisxxx = xxx;
}

  Xprototype = new O();

  x = new X();

  obj = { a : a b : b };
obj = { x : x };
$extend(true obj obj);

  alert(objxyyy); // 得到"xxx"
objxyyy = zzz;
alert(objxyyy); // 得到"zzz"
</script>

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


From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19999.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.