web前端之精通dojo四:JavaScript中的语言扩展

86 篇文章 0 订阅
15 篇文章 0 订阅

web前端之精通dojo四:JavaScript中的语言扩展

Dojo提供了一些函数库,不严格地讲,这些函数扩展了JavaScript核心库。这些函数不正对某个特定的问题领域,它们是JavaScript编程的基础。它们也处在Dojo依赖层次结构的最底层

利用dojo.hitch实现绑定:

把一个对象的方法作为参数传递给另一个函数,dojo.hitch解决了这个把方法与特定上下文绑定的问题。

绑定上下文:

上文提到了,把一个对象(o)的一个方法(m)作为参数传递给某些函数,这些函数将会调用o.m。

var theAccumulator={
    total:0
    ,clear:function(){
        this.total=0;
    }
    ,add:function(x){
        this.total += x;
    }
    ,getResult:function(){
        return this.total;
    }
};

有了上面的代码,我们将theAccumulator把100和200相加,并把theAccumulator.getResult获取:

var theAccumulator={
    total:0
    ,clear:function(){
        this.total=0;
    }
    ,add:function(x){
        this.total += x;
    }
    ,getResult:function(){
        return this.total;
    }
};
function printResult(f){
    alert("result="+f());
}
theAccumulator.clear();
theAccumulator.add(100);
theAccumulator.add(200);
printResult(theAccumulator.getResult());//出错

问题的主要原因,当把theAccumulator.getResult传给printResult时,这个函数没有绑定上下文。因此,当printResult调用参数f时,this引用的是全局对象空间,这样计算用的是全局变量total,而不是theAccumulator中的total属性。

使用printResult(function(){return theAccumulator.getResult();});就可以获得想要的total值。

当printResult调用函数function(){return theAccumulator.getResult();}时,getResult被显示地绑定到theAccumulator,消息框中正如所期望的那样显示“result=300”。

开始dojo.hitch:

dojo.hitch函数可以帮助我们创建这样的小型函数。目前我们仅考虑dojo.hitch接受一个或两个参数的情形(随后将提及多个参数的情形)。在接收两个参数时,第一个参数(一个对象)提供了第二个参数(一个函数或者表示函数的字符串)执行的上下文。dojo.hitch接受这些参数并返回一个函数,该函数在第一个参数提供的上下文中调用第二个参数。下面代码就实现了dojo.hitch实现的细节:

dojo.hitch(o,o.f);
    //o是一个对象,f是o的一个成员函数,将返回:
    function(){return o.f.apply(o,arguments);}
dojo.hitch(o,f);
    //o是一个对象,f是o的一个成员函数的名称,将返回:
    function(){return o["f"].apply(o,arguments);}

上面两种形式的区别在于第二个参数。前者的第二个参数是一个标识符,而后者的第二个参数是一个字符串。由上面的代码可以看出,当第二个参数是一个参数的成员函数时,第二种形式更为简洁。
所以我们可以把上文中printResult(function(){return theAccumulator.getResult();});改写成printResult(dojo.hitch(theAccumulator,”getResult”));

通常我们总是把一个对象的成员函数绑定到该对象本身,但是将一个普通函数或成员函数绑定到其他类型的对象也是完全合法的

dojo.hitch(o,f)
    //o是一个对象,f是一个函数,将返回
    function(){return f.apply(o,arguments);}
dojo.hitch(o,p.f)
    //o,p都是对象,o!=p,f是p的一个成员函数,返回
    function(){return p.f.apply(o,arguments);}

按照定义,这种绑定使函数f在o的上下文中执行,但f并非o的成员函数。你可以把它看做是一种动态的、单个函数的混合(如同mixin一样)。

function showData(){
    var x=this.getData();
    dojo.byId("showData").innerHTML="The result= "+x;
}
//生成1,2,3
var dataSrc1={
    value=0
    ,getData:function(){return this.value++;}
};
//生成5,10,15
var dataSrc2={
    value=0
    ,getData:function(){return (this.value+=5);}
};

要注意showData被调用时所显示的数据依赖于this引用。因此,showData必须绑定到一个定义了getData方法的上下文,showData显示的数据随其绑定的上下文不同而不同。

dojo.byId("f3").onclick=dojo.hitch(dataSrc1,showData);
dojo.byId("f4").onclick=dojo.hitch(dataSrc2,showData);

最后我们给出一个实例,利用dojo.hitch把showData绑定到这些不同的数据源,并且返回结果设置为点击事件的回调函数

绑定事件:

函数执行的上下文完全可以看做是函数的一个参数。既然我们可以利用dojo.hitch绑定上下文,那么也可以绑定其它的参数。

dojo.byId(“someId”).click=handler(someArg);

这个方法行不通,因为该语句会立即执行handler(someArg)的函数作为处理函数,所以我们使用函数字面量改成:

dojo.byId(“someId”).click=function(){handler(someArg);};

跟绑定上下文一样,dojo.hitch可以帮助我们创建一些小巧的技巧。如果你香dojo.hitch绑定三个以上的参数,它将返回一个函数对象,该函数对象在指定的上下文中以给定的参数调用作为参数传入的函数。

dojo.hitch(context,f,a1,a2,a3,...,an);//返回....
    function(){return context.f.apply(
        context,[a1,a2,a3,...,an].concat(arguments));}

JavaScript 1.6的数组方法:

dojo.indexOf:返回数组中匹配元素首次出现的位置,如果未找到返回-1

dojo.lastIndexOf:返回数组中匹配元素最后一次出现的位置,如果未找到返回-1

dojo.every:测试是否数组中所有元素都使都使测试函数返回true

dojo.some:测试数组是否有元素使测试函数返回true

dojo.filter:创建一个由数组中所有通过过滤函数的元素构成的新数组

dojo.map:创建一个对数组中的元素依次调用一个函数得到的返回值构成的新数组

dojo.forEach:将数组中的每一个元素都传递给函数

使用dojo函数有很多好处。首先,代码整洁并且语义清晰;其次,可以降低犯下许多常见的编程错误的可能性。

dojo.every、dojo.some、dojo.filter、dojo.map、dojo.forEach都遍历整个数组,在数组的每一个元素上应用一个函数(回调函数)并获取结果。上诉这些函数都有一个相同的签名:

(a,f,context),这里a表示一个数组,f表示一个回调函数,context(可选)表示执行f的上下文。在给定f和context的情况下,获得回调函数的有效方法就是地哦啊用dojo.hitch(context,f)。

同样的,我们的回调函数也有相应的签名:(item,index,array),这里item和index分别表示当前迭代中的数组元素和它的索引,array表示数组

dojo.forEach(theArray,function(x){
    //对每一个数组元素调用一次
    //对x也就是Array[i]做一些有趣的事
});

支持多态:

多态使我们调用一个函数时,可以根据参数的类型来控制函数的行为。在大多数情况下,多态函数根据单一类型确定它的行为。构造这样的多态函数很容易--只需要为支持该多态函数的类型定义这个函数即可。但是,在以下情况下,这种方法并不适用。

在类型定义中不能添加多态函数(例如,类型接口不受控或者完全封闭,或者多态函数依赖于某些该类型中没有提供的概念成分)函数的行为依赖于多个参数的类型。

在上述的两种情况下,我们只能按照多个参数的类型创建不同的执行路径。大多数情况下,你可能会使用JavaScript中的instanceof操作符确定参数类型。有时,instanceof对基本类型无效。例如:

function t1(theObject){
    return (theObject instanceof String);
}
function t2(theObject){
    return (typeof theObject=="String");
}
var b;
b=t1("test");//b是false
b=t2("test");//b是true
s=new String("test");
b=t1(s);//b是true
b=t2(s);//b是false

有些浏览器的JavaScript解析器本身就存在一些缺陷,这使上述问题在某些类型(例如:在Safari中确定一个对象是否是函数)上变得更糟。

Dojo提供了以下一系列函数来解决所有类似问题:

dojo.isString(test):如果test是字符串字面量或字符串对象,返回true

dojo.isArray(test):如果test是数组或者继承自数组,返回true

dojo.isFunction(test):如果test是函数或者继承自函数,返回true

dojo.isObject(test):如果test是null、对象、数组或函数,返回true

dojo.isArrayLike(test):如果test是包含一个长度有限的、非字符串、非函数、非DOM节点的属性,则返回true

dojo.isAlien(test):如果test本应被报告为一个函数而实际上却没有,则返回true

组合、结构化和复制对象:

后续我们将用dojo.declare构建可以创建不同类型对象的构造函数。dojo.declare提供的功能远远超出了我们的需要,例如把一个对象的属性复制到另一个对象上。Dojo预定义了一些轻量函数完成逐个对象的结构个内容操作。

混合对象:

dojo.mixin(dest,src1,src2,…);函数把src1,、src2等对象中的所有属性都复制到dest中。肤质是利用JavaScript中的赋值操作符完成的。因此,数值、布尔值和字符串都是值复制,而其他的所有类型都是引用复制。

myObject.p1=123.456;
myObject.p2="hello Word";
myObject.someprop=yourObject;
dojo.mixin(myObject,{
    p1=123.456;
    p2="hello Word";
    someprop=yourObject;
});
//当然对于对象也适用
myObject.p1=yourObject.p1;
myObject.p2=yourObject.p2;
myObject.someprop=yourObject.someprop;
dojo.mixin(myObject,yourObject);

myObject={p:1};
dojo.mixin(myObject,{p:2},{p:3});
//这时myObject设置为3

关于mixin要注意一些事情。首先,如果目标对象已经包含了一个属性,而这个属性也在源对象中存在,那么目标对象的属性会被覆盖。其次,当有多个源对象时,最右的源对象会覆盖其他所有对象的同名属性。

复制对象:

有时需要按值复制一个变量。如果这个变量是数值、布尔值或字符串就很容易得到,因为JavaScript赋值操作本身就具有按值复制的语义。但是,如果你需要复制其他类型的,JavaScript操作可能就行不通了(要知道,赋值操作对于数值、布尔值和字符串以外的类型都按引用复制)。你必须便利整个对象,包括所有内嵌对象,并为每个你访问到的节点创建新的实例。dojo.clone(src)函数实现了这个功能。

为了形象地说明assigning、mixing和cloning的区别,我们将创建一个对象,展示复制技术,并画出结果的对象空间。为完全展示他们的不同我们让源对象包含另一个对象。下面是示例代码:

//创建一个包含多个属性的对象
var bicester={city:"Bicester",country:"UK"};
var attraction={name:"Bienheim Jobs",cost:15,location:bicester};
var try1,try2,try3;
try1=attraction;//直接复制
try2=dojo.mixin({},attraction);//使用dojo.mixin进行复制
try3=dojo.clone(attraction);//使用dojo.clone进行复制 

try1=attraction和try2=dojo.mixin({},attraction)这两种复制只是给源对象添加了另一个名字[这就是所谓的浅复制],try3=dojo.clone(attraction)确保完整地创建一个对象[这就是所谓的深复制]

最后一种类型的复制使我们偶尔会遇到的,就是将类似数组的对象(例如,内建的arguments对象)转变成为一个真正的数组。dojo.toArrays(src,start)函数创建一个数组,并用src[start],src[start+1],…,src[src.length-1]填充数组。start参数是可选的,如果未提供,默认取值为0.可见源对象的要求是,它必须是一个对象并且包含整数类型的length类型。在Dojo函数中,名称以下划线开始的函数被认为是“一种”私有函数。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值