现在的位置: 首页 > 综合 > 正文

Javascript笔记:(实践篇)从jQuery插件技巧说起-深切解析extend办法(中篇)

2014年11月24日 ⁄ 综合 ⁄ 共 21728字 ⁄ 字号 评论关闭
文章目录

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源代码。

【上篇】
【下篇】

抱歉!评论已关闭.