成人精品一区二区三区中文字幕-成人精品一区二区三区-成人精品一级毛片-成人精品亚洲-日本在线视频一区二区-日本在线视频免费

導航首頁 ? 技術教程 ? 深入理解jquery中extend的實現(xiàn)
全站頭部文字 我要出現(xiàn)在這里
深入理解jquery中extend的實現(xiàn) 792 2024-02-08   

Jquery的擴展方法extend是我們在寫插件的過程中常用的方法,該方法有一些重載原型,下面來看看詳細的介紹吧。

通常我們使用jquery的extend時,大都是為了實現(xiàn)默認字段的覆蓋,即若傳入某個字段的值,則使用傳入值,否則使用默認值。

如下面的代碼:

function getOpt(option){
 var _default = {
 name : 'wenzi',
 age : '25',
 sex : 'male'
 }
 $.extend(_default, option);
 return _default;
}
getOpt(); // {name: "wenzi", age: "25", sex: "male"}
getOpt({name:'bing'}); // {name: "bing", age: "25", sex: "male"}
getOpt({name:'bing', age:36, sex:'female'}); // {name: "bing", age: 36, sex: "female"}

那現(xiàn)在我們就得需要知道這個extend具體是怎么實現(xiàn)的了,除了實現(xiàn)上面的功能,還有其他作用么?那肯定是有的啦,否則我也不會問那句話了((⊙?⊙)b)。我們先來看看extend主要有哪些功能,然后再看實現(xiàn)這些功能的原理。

1. extend能實現(xiàn)的功能

其實從extend的含義里,我們就能知道extend是做什么的了。extend翻譯成漢語后就是:延伸、擴展、推廣。

1.1 將兩個或更多對象的內容合并到第一個對象

我們來看看$.extend()提供的參數:jQuery.extend( target [, object1 ] [, objectN ] ),extend方法需要至少傳入一個參數,第一個必需,后面的都是可選參數。若傳給extend是兩個或兩個以上的參數都是對象類型,那么就會把后面所有對象的內容合并給target(第一個對象)上。

我們再來看看上面的例子:

function getOpt(option){
 var _default = {
 name : 'wenzi',
 age : '25',
 sex : 'male'
 }
 `$.extend(_default, option);`
 return _default;
}

$.extend()中接收了兩個參數_default和option,那么extend方法執(zhí)行時,就會把option對象上字段的值全給了_default。于是_default上設置的默認值就會被option上的值覆蓋。當然,若option上沒有這個字段,就不會覆蓋_default上字段的值。
上面函數中的extend,只是傳入了兩個參數,那傳的參數再更多一些呢:

function getOpt(target, obj1, obj2, obj3){
 $.extend(target, obj1, obj2, obj3);
 return target;
}

var _default = {
 name : 'wenzi',
 age : '25',
 sex : 'male'
}
var obj1 = {
 name : 'obj1'
}
var obj2 = {
 name : 'obj2',
 age : '36'
}
var obj3 = {
 age : '67',
 sex : {'error':'sorry, I dont't kown'}
}
getOpt(_default, obj1, obj2, obj3); // {name: "obj2", age: "67", sex: {error: "sorry, I dont't kown"}}

這里我們傳入了4個參數,然后getOpt()返回第一個參數的值。從運行的得到結果我們可以看到,屬性值永遠是最后一個屬性的值。

還有很重要的一點,$.extend()其實是有返回值的,返回的就是修改后的第一個參數的值。如我們可以把上面的函數修改成這樣:

function getOpt(target, obj1, obj2, obj3){
 var result = $.extend(target, obj1, obj2, obj3); 
 return result; // // result即修改后的target值
}

若我們傳入的參數不想被修改,我們可以用一個空對象來作為第一個參數,然后獲取$.extend()的返回值:

function getOpt(target, obj1, obj2, obj3){
 var result = $.extend({}, target, obj1, obj2, obj3); 
 return result; // // result即為{}修改后的值
}

1.2 為JQUERY擴展方法或屬性

剛才我們在1.1中講的$.extend()的例子都是傳了兩個或兩個以上的參數,但其實只有一個參數是必須的。若只傳一個參數會怎樣呢。

如果只有一個參數提供給$.extend() ,這意味著目標參數被省略。在這種情況下,jQuery對象本身被默認為目標對象。這樣,我們可以在jQuery的命名空間下添加新的功能。這對于插件開發(fā)者希望向 jQuery 中添加新函數時是很有用的。

$.extend({
 _name : 'wenzi',
 _getName : function(){
 return this._name;
 }
})

$._name; // wenzi
$._getName(); // wenzi

這樣我們就為jQuery擴展了_name屬性和_getName方法。

1.3 深度拷貝和淺度拷貝

針對什么是深度拷貝,什么是淺度拷貝,我們先來看一個簡單的例子。

var obj = {name:'wenzi', sex:'male'};
var obj1 = obj; // 賦值
obj1.name = 'bing';
console.log(obj.name); // bing

我們修改了obj1中的name值,結果obj中的值也跟著發(fā)生了變化,這是為什么呢。其實這就是淺度拷貝:這僅僅是將obj對象的引用地址簡單的復制了一份給予變量 obj1,而并不是將真正的對象克隆了一份,因此obj和obj1指向的都是同一個地址。當修改obj1的屬性或給obj1添加新屬性時,obj都會受到影響。

可是如果變量的值不是對象和數組,修改后面的變量是不會影響到前面的變量:

var s = 'hello';
var t = s;
t = 'world';
console.log(s); // hello

那么深度拷貝就不是拷貝引用地址,而是實實在在的復制一份新對象給新的變量。 在上面使用$.extend()中,都是使用的淺度拷貝,因此若后面的參數值是object類型或array類型,修改_default(target)的值,就會影響后面參數的值。

如我們使用getOpt(_default, obj1, obj2, obj3);得到的_default值是{name: “obj2”, age: “67”, sex: {error: “sorry, I dont't kown”}},可是若:

_default.sex.error = 'hello world';

那么obj3.sex.error也會跟著修改,因為obj3.sex是一個object類型。

不過$.extend()也提供了深度拷貝的方法:jQuery.extend( [deep ], target, object1 [, objectN ] ) 。若第一個參數是boolean類型,且值是true,那么就會把第二個參數作為目標參數進行合并。

var obj = {name:'wenzi', score:80};
var obj1 = {score:{english:80, math:90}}
$.extend(true, obj, obj1);
obj.score.english = 10;
console.log(obj.score.english); // 10
console.log(obj1.score.english); // 80

執(zhí)行后我們發(fā)現(xiàn),無論怎么修改obj.score里的值,都不會影響到obj1.score了。

2. jQuery中extend實現(xiàn)原理

其實不看源碼,對extend大致的過程應該也是了解的:對后一個參數進行循環(huán),然后把后面參數上所有的字段都給了第一個字段,若第一個參數里有相同的字段,則進行覆蓋操作,否則就添加一個新的字段。

下面是jQuery中關于extend的源碼,我就在源碼上進行注釋講解了,隨后再在后面進行總結:

// 為與源碼的下標對應上,我們把第一個參數稱為`第0個參數`,依次類推
jQuery.extend = jQuery.fn.extend = function() {
 var options, name, src, copy, copyIsArray, clone,
 target = arguments[0] || {}, // 默認第0個參數為目標參數
 i = 1, // i表示從第幾個參數凱斯想目標參數進行合并,默認從第1個參數開始向第0個參數進行合并
 length = arguments.length,
 deep = false; // 默認為淺度拷貝

 // 判斷第0個參數的類型,若第0個參數是boolean類型,則獲取其為true還是false
 // 同時將第1個參數作為目標參數,i從當前目標參數的下一個
 // Handle a deep copy situation
 if ( typeof target === "boolean" ) {
 deep = target;

 // Skip the boolean and the target
 target = arguments[ i ] || {};
 i++;
 }

 // 判斷目標參數的類型,若目標參數既不是object類型,也不是function類型,則為目標參數重新賦值 
 // Handle case when target is a string or something (possible in deep copy)
 if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
 target = {};
 }

 // 若目標參數后面沒有參數了,如$.extend({_name:'wenzi'}), $.extend(true, {_name:'wenzi'})
 // 則目標參數即為jQuery本身,而target表示的參數不再為目標參數
 // Extend jQuery itself if only one argument is passed
 if ( i === length ) {
 target = this;
 i--;
 }

 // 從第i個參數開始
 for ( ; i < length; i++ ) {
 // 獲取第i個參數,且該參數不為null和undefind,在js中null和undefined,如果不區(qū)分類型,是相等的,null==undefined為true,
 // 因此可以用null來同時過濾掉null和undefind
 // 比如$.extend(target, {}, null);中的第2個參數null是不參與合并的
 // Only deal with non-null/undefined values
 if ( (options = arguments[ i ]) != null ) {
 
 // 使用for~in獲取該參數中所有的字段
 // Extend the base object
 for ( name in options ) {
 src = target[ name ]; // 目標參數中name字段的值
 copy = options[ name ]; // 當前參數中name字段的值

 // 若參數中字段的值就是目標參數,停止賦值,進行下一個字段的賦值
 // 這是為了防止無限的循環(huán)嵌套,我們把這個稱為,在下面進行比較詳細的講解
 // Prevent never-ending loop
 if ( target === copy ) {
  continue;
 }

 // 若deep為true,且當前參數中name字段的值存在且為object類型或Array類型,則進行深度賦值
 // Recurse if we're merging plain objects or arrays
 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
  // 若當前參數中name字段的值為Array類型
  // 判斷目標參數中name字段的值是否存在,若存在則使用原來的,否則進行初始化
  if ( copyIsArray ) {
  copyIsArray = false;
  clone = src && jQuery.isArray(src) ? src : [];

  } else {
  // 若原對象存在,則直接進行使用,而不是創(chuàng)建
  clone = src && jQuery.isPlainObject(src) ? src : {};
  }

  // 遞歸處理,此處為2.2
  // Never move original objects, clone them  
  target[ name ] = jQuery.extend( deep, clone, copy );

 // deep為false,則表示淺度拷貝,直接進行賦值
 // 若copy是簡單的類型且存在值,則直接進行賦值
 // Don't bring in undefined values
 } else if ( copy !== undefined ) {
  // 若原對象存在name屬性,則直接覆蓋掉;若不存在,則創(chuàng)建新的屬性
  target[ name ] = copy;
 }
 }
 }
 }

 // 返回修改后的目標參數
 // Return the modified object
 return target;
}; 

源碼分析完了,下面我們來講解下源碼中存在的幾個難點和重點。

2.1 若參數中字段的值就是目標參數,停止賦值

在源碼中進行了一下這樣的判斷:

// Prevent never-ending loop
if ( target === copy ) {
 continue;
}

為什么要有這樣的判斷,我們來看一個簡單的例子,如果沒有這個判斷會怎么樣:

var _default = {name : 'wenzi'};
var obj = {name : _default}
$.extend(_default, obj);
console.log(_default);

輸出的_default是什么呢:

_default = {name : _default}; 

_default是object類型,里面有個字段name,值是_default,而_default是object類型,里面有個字段name,值是_default……,無限的循環(huán)下去。于是jQuery中直接不進行操作,跳過這個字段,進行下一個字段的操作。

2.2 深度拷貝時進行遞歸處理

我們在前面稍微的講解了一下,變量值為簡單類型(如number, string, boolean)進行賦值時是不會影響上一個變量的值的,因此,如果當前字段的值為Object或Array類型,需要對其進行拆分,直到字段的值為簡單類型(如number, string, boolean)時才進行賦值操作。

3. $.extend()與$.fn.extend()

上面講解的全都是$.extend(),根本就沒講$.fn.extend() 。可是,你有沒有發(fā)現(xiàn)一個細節(jié),在這段代碼的第一行是怎么寫的:

jQuery.extend = jQuery.fn.extend = function(){}

也就是說$.extend()與$.fn.extend()共用的是同一個函數體,所有的操作都是一樣的,只不過兩個extend使用的對象不同罷了:$.extend()是在jQuery($)上進行操作的;而$.fn.extend()是在jQuery對象上進行操作的,如$(‘div').extend()

4. 總結

這就是jQuery中extend的實現(xiàn),以后若我們需要用到上面的功能時,除了使用$.extend() ,我們也可以在不引入jQuery框架的情況下,自己寫一個簡單的extend()來實現(xiàn)上面的功能。

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。


主站蜘蛛池模板: 最后的朋友| 阿芮尔·温特| 大浴女电视剧所有演员表| 黄雀电视剧高清完整版| 护校队申请书| 噜啊噜在线视频| 大连酒店| 怂包| 密会韩剧| 孤岛惊魂| 三夫 电影| 饭店装修效果图| 日本xxx.| 林正英僵尸先生电影在线观看| 我不再什么作文500字| 男插女b视频| 爱在一起麻辣烫| 正在行动| 男国少年梦 电影| 贵阳三中| 美丽的错误| 暗恋桃花源剧本| av电影网| 民国电影| 李白电影| 美国电影waseas| 松岛菜菜子| 钢铁侠全防4.0| 老男人gay同性gay做受| 妻子的电视剧| 变形金刚1免费完整版在线观看| 舌尖上的中国4| 抖音网页版登录官网| 山东生活频道| 安息2| 陈一龙电视剧全集| 台湾卫视| 女生扣b视频| 斯科| 五猖会原文加批注图片| 电影《exotica》完整版观看|

!!!站長長期在線接!!!

網站、小程序:定制開發(fā)/二次開發(fā)/仿制開發(fā)等

各種疑難雜癥解決/定制接口/定制采集等

站長微信:lxwl520520

站長QQ:1737366103