1. 程式人生 > >Javascript筆記:(實踐篇)從jQuery外掛技巧說起-深切解析extend辦法(中篇)

Javascript筆記:(實踐篇)從jQuery外掛技巧說起-深切解析extend辦法(中篇)

1.1     對$.extend的懂得


  上方的程式碼裡我編寫jQuery外掛應用到了¥.extend辦法。這裡要講講我以前對jQuery外掛開闢的誤會,這種誤會源自於我對jQuery外掛開闢懂得的膚淺。


  在我前一家公司,有位做前端的同事很喜好把本身程式碼封裝成jQuery外掛,他曾經對我說:jQuery外掛技巧是jQuery最讓人激動聽心的技巧,關鍵就是應用extend辦法,當時我瀏覽一些關於jQuery技巧的材料,大多一開端都邑提到extend辦法的應用,可能本身進修的時辰不太細心,認為jQuery外掛技巧就是應用extend封裝好javascript程式碼,但我每次檢視jQuery手冊對extend的申明又很讓我費解,手冊上說來說去extend辦法只不過用於複製物件的辦法。


  固然上方我用extend成功寫出了一個jQuery外掛,對extend辦法懂得的困惑任然沒有廢除,是以這裡我要從文件的描述裡的內容好好的研究下extend辦法到底是咋回事。


  jQuery手冊對jQuery.extend的申明:



下面我逐句解析jQuery.extend辦法的功能。


(1)       用一個或多個其他物件來擴大一個物件,返回被擴大的物件。這句話很精闢,它概括了extend感化的精華,extend就是太上老君的煉丹爐,我們把各類不合的物件投進這個丹爐裡就會產生一個融合這些物件所有功能的超等物件,這就是extend辦法的感化,這個可以用數學公式形象的表述就是A+B=AB。s


(2)       若是不指定target,則給jQuery定名空間本身進行擴大。這有助於外掛作者為jQuery增長新辦法。要懂得這句話,就得解析下extend的引數了。在jQuery1.7的中文手冊裡把引數分為兩個版本:


  版本V1.0:target(object),[object1(object)],[objectN(object)],(圓括號裡的內容是引數的型別),引數註釋如下:



  版本V1.4: [deep(object)],target(object),object1(object),[objectN(object)],引數註釋如下:



這句話似乎有點題目,若是不指定target應當如何懂得了?是說extend辦法裡不傳值嗎?沒有引數傳入何來的給jQuery定名空間進行擴大啊。若是對比在版本V1.0裡對引數的申明,若是target是獨一的引數那麼如許的用法就是擴大jQuery的定名空間了,這個申明倒公道些,至少在前面我們寫的jQuery外掛裡應用到這個用法。後面我會把extend的用法一一做測試,看看這句話到底是翻譯錯誤了?還是我的懂得上呈現了題目。


(3)       若是第一個引數設定為true,則jQuery返回一個深層次的副本,遞迴地複製找到的任何物件。不然的話,副本會與原物件共享佈局。從這句話應當我們越來越熟悉打聽了extend辦法的本質了,extend就是一個javascript說話裡的拷貝操縱,在大多半包含物件概念的說話裡,因為物件的名稱儲存的是物件的別號換種說法就是物件的引用及該物件的地址而不是物件本身,所以當物件進行拷貝操縱時辰就存在淺拷貝和深拷貝的題目。關於淺拷貝和深拷貝我在以前的博文裡做過研究,若是還有那位童鞋不太定名二者的差別,可以參看下面的文章,文章連結如下:


java筆記:關於錯雜資料儲存的題目--根蒂根基篇:陣列以及淺拷貝與深拷貝的題目(上)


java筆記:關於錯雜資料儲存的題目--根蒂根基篇:陣列以及淺拷貝與深拷貝的題目(下)


(4)       不決義的屬性將不會被複制,然而從物件的原型持續的屬性將會被複制。第一句好懂得沒有定義過的物件屬性當然不會被複制了,因為不決義就便是沒有這個屬性,後半句也好懂得,extend辦法在做複製操縱時辰會把物件原型(prototype)持續到的屬性也加以複製。


為了懂得¥.extend辦法我逐句的解析了jQuery手冊裡的申明,細心回味下,extend這個可以建造jQuery外掛的辦法本來就是一個做javascript物件拷貝操縱的函式,一個物件拷貝複製函式就是外掛技巧的核心,這一會兒還真的讓人難以接管。


鑑於此,我籌算在體系講解extend辦法前先好都雅看在javascript說話裡淺拷貝和深拷貝辦法到底如何寫成的,懂了這個或許會對我們正確懂得extend的道理很有幫助。


1.2     Javascript裡的淺拷貝和深拷貝


  Javascript的賦值都是引用傳遞,就是說,在把一個物件賦值給另一個變數時辰,那麼新變數所指向的還是賦值物件本來的地址,並沒有為新物件在堆區真正的產生一個新的物件,這個就是所謂的淺拷貝深拷貝則是把本來拷貝的物件真正的複製成一個新物件,而新的變數是指向這個新物件的地址。


  下面我們就來看看javascript裡的兩種拷貝的寫法:


1.2.1    淺拷貝


程式碼如下:



// 淺拷貝測試

var scopyobj = shallowcopy({},orgval);

scopyobj.obj.content = ""New Object Value"";//改變scopyobj裡面引用物件的值

// 我們會發明scopyobj和orgval裡的obj.content的值都產生了改變

console.log(""scopyobj.obj.content:"" + scopyobj.obj.content);//scopyobj.obj.content:New Object Value

console.log(""orgval.obj.content:"" + orgval.obj.content);//orgval.obj.content:New Object Value

// 我們操縱陣列,成果是一樣的

scopyobj.arrs[1].Array02 = ""I am changed"";

console.log(""scopyobj.arrs[1].Array02:"" + scopyobj.arrs[1].Array02);//scopyobj.arrs[1].Array02:I am changed

console.log(""orgval.arrs[1].Array02:"" + orgval.arrs[1].Array02);//orgval.arrs[1].Array02:I am changed




上方的程式碼鬥勁清楚了,這裡我就不做過多的講解。


1.2.2    深拷貝


  深拷貝就鬥勁錯雜了,有個程式設計經驗的伴侶都知道經常被深拷貝糾結的資料型別其實就兩大類:物件和陣列,我們很難把握一個函式裡傳入的引數的資料型別,那麼一個編寫傑出的資料型別斷定函式就顯的首要多了,下面就是javascript一種斷定資料型別的辦法,程式碼如下:



var whatType = Object.prototype.toString;

console.log(""whatType:"" + whatType.call({""a"":12}));//whatType:[object Object]

console.log(""whatType:"" + whatType.call([1,2,3]));//whatType:[object Array]

console.log(""whatType:"" + whatType.call(1));//whatType:[object Number]

console.log(""whatType:"" + whatType.call(""123""));//whatType:[object String]

console.log(""whatType:"" + whatType.call(null));//whatType:[object Null]

console.log(""whatType:"" + whatType.call(undefined));//whatType:[object Undefined]

console.log(""whatType:"" + whatType.call(function (){}));//whatType:[object Function]

console.log(""whatType:"" + whatType.call(false));//whatType:[object Boolean]

console.log(""whatType:"" + whatType.call(new Date()));//whatType:[object Date]

console.log(""whatType:"" + whatType.call(/^[a-zA-Z0-9]{6,32}¥/));//whatType:[object RegExp]


  深拷貝會將物件內部的物件一一做複製操縱,是以深拷貝的操縱應當須要遞迴演算法,這裡我要再介紹一個函式:arguments.callee。callee 屬性是 arguments 物件的一個成員,他默示對函式物件本身的引用,這有利於匿名函式的遞迴或確保函式的封裝性,關於arguments.callee的應用,大師看下面的程式碼:



var i = 0;

function calleeDemo(){

    var whatType = Object.prototype.toString;

    i++;

    if (i < 6){

        arguments.callee();

        console.log(arguments.callee);    

        console.log(whatType.call(arguments.callee));//[object Function]    

    }

}

calleeDemo();//列印5個calleeDemo()


大師看到了arguments.callee的型別是Function,而內容就是calleeDemo()。


好了,打通了技巧難點我們來看看深拷貝的程式碼應當如何書寫了,程式碼如下:



// 深拷貝測試

var dorgval = {//測試資料

    num:1,

    str:""This is String"",

    obj:{""content"":""This is Object""},

    arrs:[""Array NO 01"",{""Array02"":""This is Array NO 02""}]

},

xQuery = {

    ""is"":function(dobj,dtype){

        var toStr = Object.prototype.toString;

        return (dtype === ""null"" && dtype === ""Null"" && dtype === ""NULL"") || (dtype === ""Undefined"" && dtype === ""undefined"" && dtype === ""UNDEFINED"") || toStr.call(dobj).slice(8,-1) == dtype;    

    },

    ""deepcopy"":function(des,src){

        forvar index in src){

            var copy = src[index];

            if (des === copy){

                continue;//例如window.window === window,會陷入死輪迴,父子彼此引用的題目    

            }

            if (xQuery.is(copy,""Object"")){

                des[index] = arguments.callee(des[index] || {},copy);

            }else if (xQuery.is(copy,""Array"")){

                des[index] = arguments.callee(des[index] || [],copy);

            }else{

                des[index] = copy;    

            }

        }

        return des;

    }

};



var dcopyobj = xQuery.deepcopy({},dorgval);

dcopyobj.obj.content = ""Deep New Object Value"";//改變dcopyobj裡面引用物件的值

// 測試

console.log(""dcopyobj.obj.content:"" + dcopyobj.obj.content);//dcopyobj.obj.content:Deep New Object Value

console.log(""dorgval.obj.content:"" + dorgval.obj.content);//dorgval.obj.content:This is Object

// 測試

dcopyobj.arrs[1].Array02 = ""Deep I am changed"";

console.log(""dcopyobj.arrs[1].Array02:"" + dcopyobj.arrs[1].Array02);//dcopyobj.arrs[1].Array02:Deep I am changed

console.log(""dorgval.arrs[1].Array02:"" + dorgval.arrs[1].Array02);//dorgval.arrs[1].Array02:This is Array NO 02


既然我們本身寫出來了javascript的深拷貝和淺拷貝,那麼我們再去研究jQuery裡的深淺拷貝操縱必然會事半功倍的。


1.3     ¥.extend用法臚陳


下面我借用jQuery手冊裡的例項程式碼來講解¥.extend的用法。


(1) 測試01:引數個數為2,並且引數型別都是object,程式碼如下:



<script type="text/javascript">

¥(document).ready(function(xj){//為¥定義一個別號xj,防止¥衝突

    // 測試01:引數個數為2,並且引數都是object型別

    console.log(""==================測試01 start"");

    var settings = {""validate"":false,""limit"":5, ""name"":"foo"},

        opts = {""validate"":true,""name"":""bar""};

    console.log(xj.extend(settings,opts));//Object { validate=true, limit=5, name="bar"}

    console.log(settings);//Object { validate=true, limit=5, name="bar"}

    console.log(opts);//Object { validate=true, name="bar"}

    // 上方的複製操縱是淺拷貝還是深拷貝

    settings = {""validate"":false,""limit"":5, ""name"":"foo"},

        opts = {""validate"":true,""name"":""bar""};

    var resobj = xj.extend(settings,opts);

    resobj.name = ""sharp"";

    console.log(resobj);//Object { validate=true, limit=5, name="sharp"}

    console.log(settings);//Object { validate=true, limit=5, name="sharp"}

    console.log(opts);//Object { validate=true, name="bar"}    

    console.log(""==================測試01 end"");

});

</script>


有上方的成果我們似乎感覺extend預設是淺拷貝,預設下extend的複製到底是淺拷貝還是深拷貝,這個須要一個應用deep標識表記標幟和不應用deep標識表記標幟的鬥勁過程,後面我將做如許的測試。下面看我第一個測試例項。


(2)  測試02:多引數,這裡我應用4個引數,引數型別都是object:



    // 測試02:多引數,這裡我應用4個引數,引數型別都是object

    console.log(""==================測試02 start"");

    var empty = {},

        defaults = {""validate"":false,""limit"":5,""name"":"foo"},

        secopts = {""validate"":true,""name"":"bar"},

        thirdopts = {""id"":""JQ001"",""city"":""shanghai""};

    var secsets = xj.extend(empty,defaults,secopts,thirdopts);

    console.log(empty);//Object { validate=true, limit=5, name="bar",id="JQ001",city="shanghai"}

    console.log(secsets);//Object { validate=true, limit=5, name="bar",id="JQ001",city="shanghai"}

    console.log(defaults);//Object { validate=false, limit=5, name="foo"}

    console.log(secopts);//Object { validate=true, name="bar"}

    console.log(thirdopts);//Object { id="JQ001", city="shanghai"}

    console.log(""==================測試02 end"");


(3) 測試03 :淺拷貝測試,引數為3,第一個是是否深淺拷貝的標識表記標幟,後面兩個是物件,程式碼如下:



    // 測試03  淺拷貝測試,引數為3,第一個是是否深淺拷貝的標識表記標幟,後面兩個是物件

    console.log(""==================測試03 start"");

    var shallowsets = {""validate"":false,""limit"":5, ""name"":"foo"},

        shallowopts = {""validate"":true,""name"":""bar""};

    console.log(xj.extend(false,shallowsets,shallowopts));//Object { validate=true, limit=5, name="bar"}

    console.log(shallowsets);//Object { validate=false, limit=5, name="foo"}

    console.log(shallowopts);//Object { validate=true, name="bar"}

    shallowsets = {""validate"":false,""limit"":5, ""name"":"foo"},

    shallowopts = {""validate"":true,""name"":""bar""};

    var shallowresobj = xj.extend(false,shallowsets,shallowopts);

    shallowresobj.name = ""ok"";

    console.log(shallowresobj);//Object { validate=true, limit=5, name="ok"}

    console.log(shallowsets);//Object { validate=false, limit=5, name="foo"}

    console.log(shallowopts);//Object { validate=true, name="bar"}

    

    var deepsets = {""validate"":false,""limit"":5, ""name"":"foo"},

        deepopts = {""validate"":true,""name"":""bar""};

    console.log(xj.extend(true,deepsets,deepopts));//Object { validate=true, limit=5, name="bar"}

    console.log(deepsets);//Object { validate=true, limit=5, name="bar"}

    console.log(deepopts);//Object { validate=true, name="bar"}

    deepsets = {""validate"":false,""limit"":5, ""name"":"foo"},

    deepopts = {""validate"":true,""name"":""bar""};

    var deepresobj = xj.extend(true,deepsets,deepopts);

    deepresobj.name = ""okdeep"";

    console.log(deepresobj);//Object { validate=true, limit=5, name="okdeep"}

    console.log(deepsets);//Object { validate=true, limit=5, name="okdeep"}

    console.log(deepopts);//Object { validate=true, name="bar"}

    console.log(""==================測試03 end"");



上方的成果讓我困惑了,當我把deep引數設定為false時辰,extend的返回值和target的值不一致,extend辦法的返回值是終極拷貝的成果,而target還是本來的值,並且我去更改返回成果的值時辰,target沒有被影響。當deep引數為true的成果和我們不設定deep的成果一樣,那麼我們可以這麼懂得了,預設下extend履行的是深拷貝操縱,然則這個結論我還不想過早給出,後面我會解析extend辦法的原始碼,研究完了原始碼我再給出本身的結論。


以上的例子都是用物件做引數,陣列的成果和物件一樣,所以這裡不再寫關於陣列的測試程式碼,下面我會應用字串以及數字型別做測試,看看extend返回的成果是咋樣的。


(4)   測試04:引數個數為2,引數型別都是字串


程式碼如下:



    // 測試04:引數個數為2,引數型別都是字串

    console.log(""==================測試04 start"");    

    var strsets = ""strsets"",stropts = ""opts"";

    var strobj = xj.extend(strsets,stropts);

    console.log(strobj);//Object { 0="o", 1="p", 2="t", 3="s"}

    console.log(strsets);//strsets

    console.log(stropts);//opts

    strsets = ""strsets"",stropts = ""opts"";

    strobj = xj.extend(false,strsets,stropts);

    console.log(strobj);//Object { 0="o", 1="p", 2="t", 3="s"}

    console.log(strsets);//strsets

    console.log(stropts);//opts

    strobj = xj.extend(true,strsets,stropts);

    console.log(strobj);//Object { 0="o", 1="p", 2="t", 3="s"}

    console.log(strsets);//strsets

    console.log(stropts);//opts

console.log(""==================測試04 end"");    


拷貝的都是字串,應用extend真的沒啥意義了,這個反過來也申明extend辦法只是針對引用型別的資料做拷貝操縱。


(5)  測試05:引數個數為2,target是字串,第二個是object型別,


程式碼如下:



    // 測試05:引數個數為2,target是字串,第二個是object型別

    console.log(""==================測試05 start"");

    var targetstr = ""sharpxiajun"",

        desobj08 = {""validate"":false,""limit"":5, ""name"":"foo"};

    console.log(xj.extend(targetstr,desobj08));//Object { validate=false, limit=5, name="foo"}

    console.log(targetstr);//sharpxiajun    

    targetstr = ""sharpxiajun"",

    desobj08 = {""validate"":false,""limit"":5, ""name"":"foo"};

    console.log(xj.extend(false,targetstr,desobj08));//Object { 0="s", 1="h", 2="a", 更多...}

    console.log(targetstr);//sharpxiajun    

    targetstr = ""sharpxiajun"",

    desobj08 = {""validate"":false,""limit"":5, ""name"":"foo"};

    console.log(xj.extend(true,targetstr,desobj08));//Object { validate=false, limit=5, name="foo"}

    console.log(targetstr);//sharpxiajun    

    console.log(""==================測試05 end"");


這裡要重視的是當deep設定為false,extend返回的成果不合,原因我如今說不清,看來從概況應用角度還是很難解析extend辦法的道理,必然得從原始碼角度進行研究了。


最後我將完全的程式碼貼出來,便於大師測試應用:



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>jQuery Copy Study</title>

</head>

<script type="text/javascript" src="js/jquery-1.7.1.js"></script>

<body>

</body>

</html>

<script type="text/javascript">

¥(document).ready(function(xj){//為¥定義一個別號xj,防止¥衝突

    // 測試01:引數個數為2,並且引數都是object型別

    console.log(""==================測試01 start"");

    var settings = {""validate"":false,""limit"":5, ""name"":"foo"},

        opts = {""validate"":true,""name"":""bar""};

    console.log(xj.extend(settings,opts));//Object { validate=true, limit=5, name="bar"}

    console.log(settings);//Object { validate=true, limit=5, name="bar"}

    console.log(opts);//Object { validate=true, name="bar"}

    // 上方的複製操縱是淺拷貝還是深拷貝

    settings = {""validate"":false,""limit"":5, ""name"":"foo"},

        opts = {""validate"":true,""name"":""bar""};

    var resobj = xj.extend(settings,opts);

    resobj.name = ""sharp"";

    console.log(resobj);//Object { validate=true, limit=5, name="sharp"}

    console.log(settings);//Object { validate=true, limit=5, name="sharp"}

    console.log(opts);//Object { validate=true, name="bar"}    

    console.log(""==================測試01 end"");

    

    // 測試02:多引數,這裡我應用4個引數,引數型別都是object

    console.log(""==================測試02 start"");

    var empty = {},

        defaults = {""validate"":false,""limit"":5,""name"":"foo"},

        secopts = {""validate"":true,""name"":"bar"},

        thirdopts = {""id"":""JQ001"",""city"":""shanghai""};

    var secsets = xj.extend(empty,defaults,secopts,thirdopts);

    console.log(empty);//Object { validate=true, limit=5, name="bar",id="JQ001",city="shanghai"}

    console.log(secsets);//Object { validate=true, limit=5, name="bar",id="JQ001",city="shanghai"}

    console.log(defaults);//Object { validate=false, limit=5, name="foo"}

    console.log(secopts);//Object { validate=true, name="bar"}

    console.log(thirdopts);//Object { id="JQ001", city="shanghai"}

    console.log(""==================測試02 end"");



    // 測試03  淺拷貝測試,引數為3,第一個是是否深淺拷貝的標識表記標幟,後面兩個是物件

    console.log(""==================測試03 start"");

    var shallowsets = {""validate"":false,""limit"":5, ""name"":"foo"},

        shallowopts = {""validate"":true,""name"":""bar""};

    console.log(xj.extend(false,shallowsets,shallowopts));//Object { validate=true, limit=5, name="bar"}

    console.log(shallowsets);//Object { validate=false, limit=5, name="foo"}

    console.log(shallowopts);//Object { validate=true, name="bar"}

    shallowsets = {""validate"":false,""limit"":5, ""name"":"foo"},

    shallowopts = {""validate"":true,""name"":""bar""};

    var shallowresobj = xj.extend(false,shallowsets,shallowopts);

    shallowresobj.name = ""ok"";

    console.log(shallowresobj);//Object { validate=true, limit=5, name="ok"}

    console.log(shallowsets);//Object { validate=false, limit=5, name="foo"}

    console.log(shallowopts);//Object { validate=true, name="bar"}

    

    var deepsets = {""validate"":false,""limit"":5, ""name"":"foo"},

        deepopts = {""validate"":true,""name"":""bar""};

    console.log(xj.extend(true,deepsets,deepopts));//Object { validate=true, limit=5, name="bar"}

    console.log(deepsets);//Object { validate=true, limit=5, name="bar"}

    console.log(deepopts);//Object { validate=true, name="bar"}

    deepsets = {""validate"":false,""limit"":5, ""name"":"foo"},

    deepopts = {""validate"":true,""name"":""bar""};

    var deepresobj = xj.extend(true,deepsets,deepopts);

    deepresobj.name = ""okdeep"";

    console.log(deepresobj);//Object { validate=true, limit=5, name="okdeep"}

    console.log(deepsets);//Object { validate=true, limit=5, name="okdeep"}

    console.log(deepopts);//Object { validate=true, name="bar"}

    console.log(""==================測試03 end"");

    

    // 測試04:引數個數為2,引數型別都是字串

    console.log(""==================測試04 start"");    

    var strsets = ""strsets"",stropts = ""opts"";

    var strobj = xj.extend(strsets,stropts);

    console.log(strobj);//Object { 0="o", 1="p", 2="t", 3="s"}

    console.log(strsets);//strsets

    console.log(stropts);//opts

    strsets = ""strsets"",stropts = ""opts"";

    strobj = xj.extend(false,strsets,stropts);

    console.log(strobj);//Object { 0="o", 1="p", 2="t", 3="s"}

    console.log(strsets);//strsets

    console.log(stropts);//opts

    strobj = xj.extend(true,strsets,stropts);

    console.log(strobj);//Object { 0="o", 1="p", 2="t", 3="s"}

    console.log(strsets);//strsets

    console.log(stropts);//opts

    console.log(""==================測試04 end"");    

    

    // 測試05:引數個數為2,target是字串,第二個是object型別

    console.log(""==================測試05 start"");

    var targetstr = ""sharpxiajun"",

        desobj08 = {""validate"":false,""limit"":5, ""name"":"foo"};

    console.log(xj.extend(targetstr,desobj08));//Object { validate=false, limit=5, name="foo"}

    console.log(targetstr);//sharpxiajun    

    targetstr = ""sharpxiajun"",

    desobj08 = {""validate"":false,""limit"":5, ""name"":"foo"};

    console.log(xj.extend(false,targetstr,desobj08));//Object { 0="s", 1="h", 2="a", 更多...}

    console.log(targetstr);//sharpxiajun    

    targetstr = ""sharpxiajun"",

    desobj08 = {""validate"":false,""limit"":5, ""name"":"foo"};

    console.log(xj.extend(true,targetstr,desobj08));//Object { validate=false, limit=5, name="foo"}

    console.log(targetstr);//sharpxiajun    

    console.log(""==================測試05 end"");        

});

</script>


1.4     複製一個¥.extend辦法


  學會了jQuery外掛技巧,我們完全可以把extend辦法從原始碼裡摳出來,本身為jQuery定義一個功能和extend一模一樣的外掛,複製一個¥.extend辦法就是想應用一下編寫jQuery的技巧,這種應用也是很是有意義的,因為建造jQuery外掛讓我獲得了一種研究jQuery原始碼的體式格式,這種體式格式或許是我真正懂得jQuery原始碼的金鑰匙地點。


  下面是我外掛的程式碼,檔名稱是:jquery.xjcopy.js,程式碼如下:



;(function(¥){

    ¥.xjcopy = ¥.fn.xjcopy = function(){

        var options, name, src, copy, copyIsArray, clone,

            target = arguments[0] || {},

            i = 1,

            length = arguments.length,

            deep = false;

    

        // 若是第一個引數是布林值,那麼這是使用者在設定是否要進行深淺拷貝

        iftypeof target === "boolean" ) {

            deep = target;

            target = arguments[1] || {};

            // 若是第一個引數設定的深淺拷貝標識表記標幟,那麼i設為2,下一個引數才是我們要操縱的資料

            i = 2;

        }

    

        // 若是傳入的不是物件或者是函式,可能為字串,那麼把target = {}置為空物件

        iftypeof target !== "object" && !¥.isFunction(target) ) {

            target = {};

        }

    

        // 若是傳入的引數只有一個,跳過下面的步調

        if ( length === i ) {

            target = this;

            --i;

        }    

        

        for ( ; i < length; i++ ) {

            // 只操縱物件值非null/undefined的資料

            if ( (options = arguments[i]) != null ) {

                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 ] = ¥.xjcopy( deep, clone, copy );

    

                    } else if ( copy !== undefined ) {

                        target[ name ] = copy;

                    }

                }

            }

        }

        // 返回成果

        return target;    

    };

})(jQuery)


測試頁面xjqcopy.html程式碼如下:



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>用jQuery外掛的體式格式從頭定義一個jQuery.extend以及jQuery.fn.extend函式</title>

</head>

<script type="text/javascript" src="js/jquery-1.7.1.js"></script>

<script type="text/javascript" src="js/jquery.xjcopy.js"></script>

<body>

</body>

</html>

<script type="text/javascript">

¥(document).ready(function(){

    // 測試01:引數個數為2,並且引數都是object型別

    console.log(""==================測試01 start"");

    var settings = {""validate"":false,""limit"":5, ""name"":"foo"},

        opts = {""validate"":true,""name"":""bar""};

    console.log(¥.xjcopy(settings,opts));//Object { validate=true, limit=5, name="bar"}

    console.log(settings);//Object { validate=true, limit=5, name="bar"}

    console.log(opts);//Object { validate=true, name="bar"}

    // 上方的複製操縱是淺拷貝還是深拷貝

    settings = {""validate"":false,""limit"":5, ""name"":"foo"},

        opts = {""validate"":true,""name"":""bar""};

    var resobj = ¥.xjcopy(settings,opts);

    resobj.name = ""sharp"";

    console.log(resobj);//Object { validate=true, limit=5, name="sharp"}

    console.log(settings);//Object { validate=true, limit=5, name="sharp"}

    console.log(opts);//Object { validate=true, name="bar"}    

    console.log(""==================測試01 end"");

    

    // 測試02:多引數,這裡我應用4個引數,引數型別都是object

    console.log(""==================測試02 start"");

    var empty = {},

        defaults = {""validate"":false,""limit"":5,""name"":"foo"},

        secopts = {""validate"":true,""name"":"bar"},

        thirdopts = {""id"":""JQ001"",""city"":""shanghai""};

    var secsets = ¥.xjcopy(empty,defaults,secopts,thirdopts);

    console.log(empty);//Object { validate=true, limit=5, name="bar",id="JQ001",city="shanghai"}

    console.log(secsets);//Object { validate=true, limit=5, name="bar",id="JQ001",city="shanghai"}

    console.log(defaults);//Object { validate=false, limit=5, name="foo"}

    console.log(secopts);//Object { validate=true, name="bar"}

    console.log(thirdopts);//Object { id="JQ001", city="shanghai"}

    console.log(""==================測試02 end"");



    // 測試03  淺拷貝測試,引數為3,第一個是是否深淺拷貝的標識表記標幟,後面兩個是物件

    console.log(""==================測試03 start"");

    var shallowsets = {""validate"":false,""limit"":5, ""name"":"foo"},

        shallowopts = {""validate"":true,""name"":""bar""};

    console.log(¥.xjcopy(false,shallowsets,shallowopts));//Object { validate=true, limit=5, name="bar"}

    console.log(shallowsets);//Object { validate=false, limit=5, name="foo"}

    console.log(shallowopts);//Object { validate=true, name="bar"}

    shallowsets = {""validate"":false,""limit"":5, ""name"":"foo"},

    shallowopts = {""validate"":true,""name"":""bar""};

    var shallowresobj = ¥.xjcopy(false,shallowsets,shallowopts);

    shallowresobj.name = ""ok"";

    console.log(shallowresobj);//Object { validate=true, limit=5, name="ok"}

    console.log(shallowsets);//Object { validate=false, limit=5, name="foo"}

    console.log(shallowopts);//Object { validate=true, name="bar"}

    

    var deepsets = {""validate"":false,""limit"":5, ""name"":"foo"},

        deepopts = {""validate"":true,""name"":""bar""};

    console.log(¥.xjcopy(true,deepsets,deepopts));//Object { validate=true, limit=5, name="bar"}

    console.log(deepsets);//Object { validate=true, limit=5, name="bar"}

    console.log(deepopts);//Object { validate=true, name="bar"}

    deepsets = {""validate"":false,""limit"":5, ""name"":"foo"},

    deepopts = {""validate"":true,""name"":""bar""};

    var deepresobj = ¥.xjcopy(true,deepsets,deepopts);

    deepresobj.name = ""okdeep"";

    console.log(deepresobj);//Object { validate=true, limit=5, name="okdeep"}

    console.log(deepsets);//Object { validate=true, limit=5, name="okdeep"}

    console.log(deepopts);//Object { validate=true, name="bar"}

    console.log(""==================測試03 end"");

    

    // 測試04:引數個數為2,引數型別都是字串

    console.log(""==================測試04 start"");    

    var strsets = ""strsets"",stropts = ""opts"";

    var strobj = ¥.xjcopy(strsets,stropts);

    console.log(strobj);//Object { 0="o", 1="p", 2="t", 3="s"}

    console.log(strsets);//strsets

    console.log(stropts);//opts

    strsets = ""strsets"",stropts = ""opts"";

    strobj = ¥.xjcopy(false,strsets,stropts);

    console.log(strobj);//Object { 0="o", 1="p", 2="t", 3="s"}

    console.log(strsets);//strsets

    console.log(stropts);//opts

    strobj = ¥.xjcopy(true,strsets,stropts);

    console.log(strobj);//Object { 0="o", 1="p", 2="t", 3="s"}

    console.log(strsets);//strsets

    console.log(stropts);//opts

    console.log(""==================測試04 end"");    

    

    // 測試05:引數個數為2,target是字串,第二個是object型別

    console.log(""==================測試05 start"");

    var targetstr = ""sharpxiajun"",

        desobj08 = {""validate"":false,""limit"":5, ""name"":"foo"};

    console.log(¥.xjcopy(targetstr,desobj08));//Object { validate=false, limit=5, name="foo"}

    console.log(targetstr);//sharpxiajun    

    targetstr = ""sharpxiajun"",

    desobj08 = {""validate"":false,""limit"":5, ""name"":"foo"};

    console.log(¥.xjcopy(false,targetstr,desobj08));//Object { 0="s", 1="h", 2="a", 更多...}

    console.log(targetstr);//sharpxiajun    

    targetstr = ""sharpxiajun"",

    desobj08 = {""validate"":false,""limit"":5, ""name"":"foo"};

    console.log(¥.xjcopy(true,targetstr,desobj08));//Object { validate=false, limit=5, name="foo"}

    console.log(targetstr);//sharpxiajun    

    console.log(""==================測試05 end"");    

});

</script>


大師可以看到應用我新封裝的外掛,和extend辦法履行的成果一模一樣。


下一篇我將解析extend原始碼。

相關推薦

Javascript筆記實踐篇jQuery外掛技巧-深切解析extend辦法中篇

1.1     對$.extend的懂得   上方的程式碼裡我編寫jQuery外掛應用到了¥.extend辦法。這裡要講講我以前對jQuery外掛開闢的誤會,這種誤會源自於我對jQuery外掛開闢懂得的膚淺。   在我前一家公司,有位做前端的同事很喜好把本身程式碼封裝成jQ

筆記Git Bash ssh key配置及首次提交本地工程到githubWindows

開通頭條號-GeekerZQ 本博文使用markdown編輯生成。 一、必要條件 Windows中已安裝git; 已經註冊了github賬號。 二、ssh key生成及配置 在本地生成ssh key並配置到github網站。具體過程

劉雲浩群智感知——主動擊發,到無意識配合眾包思想的延展

引子:九華山(地藏菩薩)——達摩見梁武帝:善有善報,惡有惡報:你做了好事,也不一定是你的善報,而是有人會得善報——做善事,不要帶著功利性;做好事,不要影響自己和別人的利益。 提綱:煤礦檢測,海洋監控,綠野千傳到CitySee(劉雲浩小組在感測器網路的工作演變) 1、綠野千傳

Vue3jQuery 轉到 Vue工程化 的捷徑

# 不會 webpack 還想學 vue 工程化開發 的福音 熟悉jQuery開發的,學習vue的簡單使用是沒用啥問題的,但是學習vue的工程化開發方式,往往會遇到各種問題,比如: webpack、node、npm、cnpm、yarn、腳手架、開發環境、測試環境、生產環境、各種安裝、各種建立。 好在 vue

JavaScript筆記柯里化,資料扁平化

柯里化,扁平化 柯里化 扁平化 柯里化 在數學和電腦科學中,柯里化是一種將使用多個引數的一個函式轉換成一系列使用一個引數的函式的技術。 前端使用柯里化主要是為了簡化程式碼結構。提高系統的可維護性,一個方法,只有一個引數,強制了功能的單一性,使

JavaScript筆記最詳細的call函式和apply函式用法總結

昨天聽了一堂直播,裡面有教到關於forEach函式的原始碼編寫,提到了call()和apply()函式,有點懵,這才發現之前我學的太快了,有很多細節沒有注意,當進行實戰時才發現漏了一些東西,現在開始查漏補缺。 今天就好好總結一下call()和apply()方法的應用。首先,這兩個函式

JavaScript筆記原始值物件包裝類

原始值有數字、字串、布林值、undefined、null。 但是在JavaScript中, 數字可分為:原始值數字,數字型別物件。 字串可分為:原始值字串,字串型別物件。 布林值可分為:原始值布林值,布林值型別物件。 但是undefined、nu

JavaScript筆記列舉

JavaScript筆記列舉 列舉 for i 語句可用來遍歷一個物件中的所有屬性名,該列舉過程會列出所有的屬性,包括函式和原型中的屬性,可用 hasOwnProperty 方法過濾掉無用的屬性,可用 typeof 來排除函式。 hasOwnProperty(

javascript筆記使用者行為分析研究之資料採集 --第二種

1.1使用者行為分析的重要性   使用者行為分析的重要性,我想做個網站的人都會用很清晰的認識,本來我想談談自己想法,但感覺自己畢竟還是做技術的,很難清晰的從商業價值的角度來分析它的重要性,因此放棄了想闡述自己意見的想法。當我第一次見到百度統計,和谷歌分析網站,就有那種驚鴻一瞥的激動,很想自己也能

JavaScript筆記錯誤處理與除錯

1、瀏覽器報告的錯誤 IE IE 是唯一一個在瀏覽器的介面窗體(chrome)中顯示 JavaScript 錯誤資訊的瀏覽器。在發生 JavaScript 錯誤時,瀏覽器左下角會出現一個黃色的圖示,圖示旁邊則顯示著”Error on page”(頁面中有錯誤

深度學習系列1——線性迴歸說

為什麼先說線性迴歸 本文適合入門級同學,老司機繞行。 吳恩達老師的機器學習課程,介紹的第一個模型就是線性迴歸模型。機器學習(尤其是監督學習),主要圍繞分類和迴歸兩類問題展開,而線性迴歸模型作為最簡單的迴歸模型,與大多數監督學習演算法具有相同的建模思路,包括建

如何安裝Python中numpy,在DOS驗證下一步步解決安裝問題DOS下python的驗證到pip驗證到Numpy安裝成功

注:我在安裝過程中,按照一些博主的安裝流程,並未安裝成功。最後發現了大概是我出現的問題和其他的博主不一樣吧。反正就是要對症下藥,其實每個人的問題都不太一樣,自己設定的安裝路徑,各種許可權,各種不同的系統,都會導致問題產生,所以安裝不成功的時候,請不要沮喪,也請不要踩人,網路

Sklearn學習之路1——20newsgroups開始講

1. Sklearn 簡介 Sklearn是一個機器學習的python庫,裡面包含了幾乎所有常見的機器學習與資料探勘的各種演算法。 具體的,它常見的包括資料預處理(preprocessing)(正則化,歸一化等),特徵提取(feature_extractio

C語言重點——指標篇一文讓你完全搞懂指標| 記憶體理解指標 | 指標完全解析

> 有乾貨、更有故事,微信搜尋【**程式設計指北**】關注這個不一樣的程式設計師,等你來撩~ **注:這篇文章好好看完一定會讓你掌握好指標的本質** C語言最核心的知識就是指標,所以,這一篇的文章主題是「指標與記憶體模型」 說到指標,就不可能脫離開記憶體,學會指標的人分為兩種,一種是不瞭解記憶體

infi生命不息,奮鬥不止,萬事於忽微,量變引起質變

你只看到我在不停的忙碌,卻沒看到我奮鬥的熱情。你有朝九晚五,我有通宵達旦。你否定我的現在,我決定我的未來。你可以輕視我的存在,我會用程式碼證明這是誰的時代!夢想是註定孤獨的旅行,路上少不了質疑和嘲笑,但那又怎麼樣 。哪怕遍體鱗傷 也要coding。我是java程式設計師 我為自己代言

筆記gulp的安裝以及less外掛安裝與使用

如果是新手就請先看完全篇文章再開始動手操作,否則中間遺漏了什麼細節的話有可能導致安裝失敗或者安裝後測試時出現找不到檔案的尷尬。 相信大家再寫程式碼的時候或多或少都會遇到一個問題,比如css檔案中,某一

筆記學習Javascript閉包Closure

rip public 垃圾回收機制 不用 垃圾回收 證明 .com data 註意 閉包(closure)是Javascript語言的一個難點,也是它的特色,很多高級應用都要依靠閉包實現。 下面就是我的學習筆記,對於Javascript初學者應該是很有用的。 一、變量的作用

JavaScript高階程式設計》筆記面向物件的程式設計

面向物件的語言有一個標誌,那就是它們都有類的概念,而通過類可以建立任意多個具有相同屬性和方法的物件。 理解物件 建立自定義物件的最簡單的方法就是建立一個Object的例項,然後再為它新增屬性和方法。例如: var person = new Object(); person.name="N

JavaScript精華筆記ES5陣列新增函式的原始碼實現2

本系列文章中,對forEach、filter、map、every、some、reduce和reduceRight等函式,講述瞭如何自己編寫程式碼實現它們的功能。 通過閱讀原始碼,自己編寫原始碼,能瞭解編寫思想、熟悉設計模式,能鍛鍊自己編寫元件、框架的能力。 接上篇文章內容,這裡繼續討論如

JavaScript精華筆記ES5陣列新增函式的原始碼實現1

本篇文章中,對forEach、filter、map、Every、Some、reduce和reduceRight等函式,講述瞭如何自己編寫程式碼實現它們的功能。 通過閱讀原始碼,自己編寫原始碼,能瞭解編寫思想、熟悉設計模式,能鍛鍊自己編寫元件、框架的能力。 試驗物件 所有的函式原始