




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
语法和语义
可选的分号
标识符(Identifier)
基础数据类型和字面量(Literal)
变量的作用域
关于==,!=,===,!==
关于this,new,apply,call
关于arguments
成员访问,prototype链,继承
变量访问,callobject,Closure
总结
惯用法和技巧
编码规范和JS书写模板
页面功能的普通功能
模块需要提供给其他模块使用(单例)
模块需要提供给其他模块使用(多实例)
为继承而设计的类
继承其他类
BOM和DOM简介
BOM
DOM
jQuery学习
设计理念
Utility
选择与CSS3选择器
构造jQuery对象
jquery对象结构
基本操作
事件
操作
数据
检测
前端基础库fdevlib
style目录结构简要说明
fdev-v4现有组件
JS学习
本文目的在于为Java或有语言基础的同学参于前端开发提供指导
语法和语义
可选的分号
语句如果它们在单独一行,那么结尾的分号可以省略。
注:为了一致性和避免错误(如压缩或merge带来的错误),我们要求所有语句都要加分号(块语句和函数申明语句后不需要分号)
vara=1;
a+=1;varcallback=function(){
return'hi';
};//函数申明语句
functionother(){}for(vari=0;i<10;i++){}if(a===123){}
[注]我们不能写出这样的句子
functionabc(){
return//返回123
123;
}
abc();//->undefined
标识符(Identifier)
和Java相比,Javascript允许在标识符中使用$,所以很多库都用它来定义特殊作用的全局对象
像jQuery,Prototype,Mootools等框架使用$操作页面节点,它仅是一个普通的函数
//在jQuery中
$('#mydiva').css('color','#f00');//设置链接颜色//在旧版本的Mootools中
if($type(abc)==='string'){//新版本使用typeOf代替}//在中文站JS基础库FDEV3中
varelm=$('mydiv');//相当于document.getElementById('mydiv');
所以$可以用作有"特殊"含义的变量名
//在有些同学的代码中,用于在内部函数中访问外围对象
varTest={hi:function(){
var$this=this;//我见过的常用的名称还有that,self,me等,
//使用self有一个隐患,就是忘记了定义self时,
//会造成难以排错,因为有一个全局的self会产生干忧$.ajax(url,{
success:function(o){
o.success&&$this.render(o.data)
}
});
},render:function(){}
};
基础数据类型和字面量(Literal)
Number
123,0xf000,0377(8进制)
3.14,.222,1.2e12,1.4e-12
可以使用Math对象进行常见的科学计算,见/js/js_obj_math.asp
此外Javascript也定义了一些特殊的Number用于合适的需要,如NaN,Number.MAX_VALUE,Number.MIN_VALUE,
参考《Javascript权威指页》3.1.6
注:当使用parseInt将字符串转成整型时,请带上进制,否则如果有前缀是0,会被当成8进制处理可能不符合预期需求
varnum=parseInt(inputText,10);//如在文本框输入页码等
String
可以使用单引号或双引号两种形式varstr1='我是一个字符串,包含着双引号"';//单引号中的双引号可以不用转义,当然使用转义也木有问题varstr2="我是另一个字符串,包含着单引号'";
vartemplate=
'<div>\
<dl>\
<dt>示例1</dt>\
<dd></dd>\
<dt></dt>\
<dd></dd>\
</dl>\
</div>';
String和Number的转化技巧
parseInt('123',10);//注:请加上第二个参数'123'-0//注:不能使用+456+''
123456+'元'//->'123456元';
[String对象的方法请参考]
/jsref/jsref_obj_string.asp
Boolean
false,null,undefined,0,NaN,''在逻辑判断中都被当成false处理
varkeyword=$('#keyword').val();
if(!$.trim(keyword)){
//用户输入为空
}varnum=$('#num').val();
num=parseInt(num,10);if(!num){//NaN
//用户输入非法数字
}
Function
//申明式
functiona(){}
console.debug()//->'a'
//匿名函数
varb=function(){};
console.debug()//->''
申明式和语句式区别
fun(123);//在这里就可以使用functionfun(value){
console.debug(value);
}
b(123);//bisundefined;varb=function(){
};
ObjectLiteral
varalbum={
name:'pipixiuxiu',//注,这里的name不是变量,只是省略了单引号
‘count’:100,'private':true,//当属性名称是保留字时,必须使用这种方式234:'较少用',
12.34:'更少用'
};;
album['count'];album[234];
jQuery对象是怎么造就的?
varo={
0:elm0,
1:elm1,
2:elm2,
3:elm3,length:4,
splice:function(){}//firebug看到这个会以为它是个数组,所以显示方式和数组一样
...
}
注:使用Literal语法构造对象,而不是newObject()
varo={};//而不是newObject();
ArrayLiteral
varary=[];
ary[0]='one';
varlist=[99,'somestring',function(){}];
[Array的方法请参考]
/jsref/jsref_obj_array.asp
注:**总是使用Literal语法构造数组,而不是使用newArray()**
vararray=[];//而不是newArray();
拼接字符串,在Java中使用StringBuilder或StringBuffer拼接字符串,以减少临时对象的产生提高GC效率。
在JS中使用数据组达到这一目的。
varhtml=[];elms.each(function(){
html.push('somestring...');
});html=html.join('');
[注]在Object/Array最后一个元素后面不能加逗号,尽管这在标准上允许,但是在IE67浏览器下会报语法错误
所以,如果发现在FF下工作正常,在IE下工作不正常,请检查是否object或array最后多了个逗号
varo={
name:'pipi',
desc:'ererer',
//price:12//在调试中把这句注释了,造成上面一句最后多了个逗号
};
所以可能在某些代码中发现以下写法以避免上述错误
varo={
name:'pipi',
desc:'ererer',
//price:12,
_:0//多了一个这样的元素
};
不过我不推荐这样的形式,注意点就好,因为上述形式可能会带来其他隐患,并且可读性也不好。
可以借助工具来扫描这类错误,如JSLint:/
变量的作用域
变量在JS中是函数作用域的,而不是块作用域(C,Java,C#等是块作用域)
functionhello(){
vara=123;for(vari=0;i<10;i++){
vara=234;
//...
}console.debug(a);//->234
}
在函数作用域内定义的var都相当于在一开始定义一样
即一个函数执行时,引擎分两步操作
1.处理所有var语句(和函数申明语句),准备好执行环境,相当于这些var和function申明语句写在函数的最前面
2.执行函数内的语句
所以上述代码相当于这样:
functionhello(){
vara,
i;a=123;for(i=0;i<10;i++){
a=234;
//...
}console.debug(a);//->234
}
这会让javascript虚拟机实现closure更方便,让内存模型更简洁
functionhello(){
alert(a);//alert(undefined);if(false){
vara;
}
}等效于functionhello(){
vara;alert(a);if(false){
}
}
functionhello(){
alert(a);//ReferenceError:aisnotdefined
}
[最佳实践]
一个函数内最好只有一个var,并且尽可能靠前(最好是在函数一开始)但这与块作用域的实践,变量最好在用到的时候定义不一致
所以函数尽可能得短小,以满足前面两个条件
关于==,!=,===,!==
一句话:总是使用===和!==进行比较
因为==和!=在比较时如有必要,会进行类型转换
null==undefined//->true
'0'==false//->true
'1'==true//->truenull==false//->false
undefined==false//->false
[具体的比较规则请参考]ECMA26211.9.3
如果不想看,可能参考一条规则:null==undefined,字符串和boolean都转成数字进行比较
关于this,new,apply,call
当调用一个方法(函数时),函数内部的this指向一个对象,在规范中被称为:ThisBinding,我喜欢叫它BindObject
一般情况下,this指向调用它的那个对象或者GlobalObject,在浏览器中为window
varA={
hello:function(){
console.debug(this);
}
};A.hello();//->Avarb=A.hello;
b();//->GlobalObject,在浏览器中即是window
所以函数中的this指向和如何调用它有关系,和在哪里定义这个函数关系不大
我们可以使用call或apply方法参数化this
varA={
name:'A',functionhello(){
console.debug(this.anme);
}
};A.hello();//this===A
varB={name:'B'};A.hello.call(B);//this===B
至于call和apply的区别,只是方法支持参数的区别,功能一样
fun.apply(o,[arg1,arg2,arg3]);function.call(o,arg1,arg2,arg3);
new操作符会构造一个对象,并且让this指向它functionA(){
console.debug(this);
}A();//->windownewA();//->object,object!==window
functionPeople(name){
=name
}varp1=newPeople('p1');varp2=newPeople('p2');assert(p1!==p2);
assert(==='p1');
这里我们似乎看到了js面向对象的影子
关于new的返回值
如果function返回object,则new返回那个object,否则返回引擎构造的那个objectfunctionA(){}
newA();//->object
functionB(){
varo={};
returno;
}
newB();//->o
functionC(){
return1;//typeof1==='number',1isnotanobject
}
newC();//->object,not1
关于arguments
函数内部除this外,还有一个对象就是arguments,它是一个类数组,保存着函数的调用参数
functiona(){
varargs=arguments,
a=args[0],
b=args[3],
len=args.length;
}
我们可以对arguments进行迭代,但如果我们要使用数组的方法操作它,就需要把它转化成数组
varary=$.makeArray(arguments);//$isjQueryvarary=[].slice.call(arguments,0);//如果没有库支持
成员访问,prototype链,继承varA={name:'A',hello:function(){
console.debug('hello'+);
}};A.name;//'A'
A.hello();//'helloA'varCA=function(){
};
CA.prototype=A;varo=newCA();//读取时,如果必要,则访问prototype
;//'A'
o.hello();//'helloA'
//设置
='o';
;//'o'//找到了,就不需要访问prototype了
o.hello();//'helloo'//A未曾改变
A.name//'A'
A.hello//'helloA'
读取一个对象成员时,会走prototype链,设置一个对象成员时,对prototype无影响
比如像这样:
varA=function(){};
A.prototype={propPA:'PA'};vara=newA();
pA='A';varB=function(){};
B.prototype=a;varb=newB();
pB='B';varC=function(){};
C.prototype=b;varc=newC();
pC='C';console.debug(pC);//C
console.debug(pB);//B
console.debug(pA);//A
console.debug(pPA);//PA
console.debug(c.toString());//[objectObject]所以我们可以用prototype对象来实现类,以及用prototype链来实现继承
我们使用如下模板书写一个简单的类varA=function(){
this.init.apply(this,arguments);//代理给prototype.init
};
A.prototype={/**
*构造函数
*/
init:function(name){
=name;//对象属性
},/**
*实例方法
*/
hello:function(){
console.debug('hello'+);
}
};
JS是动态的语言,可以很方面地实现对象的功能扩展,所以比较少用继承
如果使用继承,我会使用以下方法来实现,因为代码较原型链方式来得更简单
varB=function(){
this.init.apply(this,arguments);
};
B.prototype=$.extendIf({
init:function(name,age){
A.prototype.init.call(this,name);//super(name)
this.age=age;
},say:function(){}
},A.prototype);
变量访问,callobject,Closure
在js中,变量是函数作用域的,这一点上面已讲过
这里的访问主要考虑嵌套函数的调用,即一个非常重要的特性Closurevarwelcome='welcome~~~';functionhello(name){varprefix='hello';alert(welcome);functionsay(postfix){
varmy='stringmy';alert(prefix+name);
alert(my)
alert(postfix)
}returnsay;
}varsay=hello('alibaba');
say('goodbye');
每次调用一个函数时,执行函数代码前,Js执行引擎要做些准备工作,其中会创建一个称为CallObject的对象
而调用方法的形式参数,局部变量,arguments等就成为这个对象的属性.
所以访问形式参数,局部变量,arguments就相当于访问这个对象的属性总结
JS的语言本身非常精简,整个ECMA262规范只有200页,其中有一半用来介绍了核心库的内容,
语言语法,语义,引擎的实现全部加起来也才100页.所以真的是非常地精巧,但描述能力却很强大.
引擎核心内容总结如下:
this会动态地指向BindObject,所以又称为动态作用域.我们对this属性的访问就是访问这个对象的属性.
变量的访问,其实是访问的是CallObject的属性,CallObject链根据词法结构就已确定,所以又称为静态作用域,或“词法作用域”
由于这个链在js中是不能访问的,所以又称"暗链"
对象属性(成员)的访问,遵循的是prototype链,由于这个链在js中是可以直接访问的,所以又称为"明链"
[如果对上述内容详细内容感兴趣可以参看]
*《Javascript权威指》:4.64.7
*ECMA26210.3~10.6
*/faq/notes/closures/
*我的文章:/pages/viewpage.action?pageId=47748204
惯用法和技巧
//检测空串
if(!$.trim(str)){}//字符串/数字类型转换
varstr='100';varnum=str-0;varstr2=num+'';
//空检则
if(!value){//undefined,null,false,0,'',NaN等为'空'}//逻辑或||if(!a){
a=100;
}a=a||100;//注意不能写成a||=100,虽然ruby支持if(!this.elm){
this.elm=$('#mydiv');
}this.elm=this.elm||$('#mydiv');
varpageSize=10;
if(data&&data.pageSize){
pageSize=data.pageSize;
}pageSize=(data||{}).pageSize||10;
//逻辑与&&function(success){
if(success){
success('abc');
}success&&success('abc');
}注意:不能写成options.delay&&this.delay=true;赋值运算附优先级低
可以是options.delay&&(this.delay=true);
//默认参数functionhello(options){
options=$.extend({
time:1000,
color:'#f00',
'font-size':'12px'
},options);...
}
//字符串拼接varhtml=[];
for(...){
html.push('...');
}
html=html.join('');//字符串模板
vartemplate=
'<div>\
<dl>\
<dt>示例1</dt>\
<dd></dd>\
<dt></dt>\
<dd></dd>\
</dl>\
</div>';
编码规范和JS书写模板
JS是一门动态灵活的语言,不同的同学可能写出风格完全不同的代码.
所以参考或使用此模板目的在于提高js代码一致性和可读性.
首先需要参考:前端CodeReview列表
页面功能的普通功能
如Diy皮肤功能,Js文件名为diy-skins.js
我们把文件中模块代码包含在一个自执行匿名函数中,以避免全局名字空间冲突
原则上一个文件只包含一个模块(一般是一个主类)
因为我们的merge脚本不够强,为了按需加载和减少请求数,有可能会把一个组件所有代码放在一个文件中
但是也需要把每个模块放在各自的自执行匿名函数中
/**
*旺铺Diy后台皮肤选择
*@authorqijun.weiqj
*/
(function($,WP){
[1]
varUtil=WP.Util,
UI=WP.UI,
PageSwitcher=WP.widget.PageSwitcher
...[2]
varDiySkins={[3]
init:function(){},initCatsPanel:function(){},initSkinPanel:function(){}};
[4]
WP.PageContext.register(...)//相当于//页面载入后就执行
$(function(){
Diy.Skin.init();
})})(jQuery,Platform.winport);
[1].这个区域相当于java的import区,根据需要可以alias一些用到的类
当然现在我们还需要在merge文件中包含需要的库文件.
后续我们会期望引入脚本来自动merge导入的类
像这样:
varUtil=require('widget/util'),
UI=require('widget/ui'),
ModBox=require('diy/mod-box');
[2].主模块(类/对象)名要求和js文件名尽量保持一致
[3].初始化方法或构造函数名称为init
[4].最后当页面domready时应该执行初始化方法,所以调用jquery.ready方法(在旺铺中进行一些封装,所以调用PageContext.register进入注册)
模块需要提供给其他模块使用(单例)
(function($,WP){varUI={[1]
/**
*缩放图片
*@param{jquery}selector...
*@param{int}size...
*/
resizeImage:function(selector,size){},[2]
_resize:function(){}/**
*IE6positionfixed
*/
positionFixed:function(selector){}};[3]
WP.widget.UI=UI;})(jQuery,Platform.winport);
相当于方法,可由其他模块调用
下划线带头的方法,不可由其他模块调用
挂接到相应的名字空间下,以便由外界可以使用
模块需要提供给其他模块使用(多实例)
(function($,WP){
varTabs=function(){
this.init.apply(this,arguments);
};Ttotype={init:function(tabs,bodies){},_create:function(){}
};WP.widget.Tabs=Tabs;
})(jQuery,Platform.winport);
为继承而设计的类
(function($,WP){
varDialog=function(){
this.init.apply(this,arguments);
};Dtotype={[1]
init:function(options){
..
render(this);
},[2]
close:function(){},[3]
_createButtons:function(){}
};[4]
functionrender(self){
self._createButtons();
}
WP.widget.Dialog=Dialog;
})(jQuery,Platform.winport);
[1].构造函数
[2].public方法
[3].protected方法,可由子类重写
[4].private方法
继承其他类
(function($,WP){varDialog=WP.widget.Dialog;varFormDialog=function(){
this.init.apply(this,arguments);
};
FormDtotype=$.extendIf({init:function(options){
[1]
Dtotype.init.call(this,options);
},[2]
_createButtons:function(){
Dtotype._createButtons.call(this,...);
...
},[3]
__createForm:function(){
},[4]
getData:function(){}},Dtotype);
[5]
functioncreateForm2(self){}
WP.diy.FormDialog=FormDialog;
})(jQuery,Platform.winport);
[1].调用父类构造函数
[2].重写父类方法,调用父类方法
[3].private方法
[4].public方法
[5].private(和3选择一种形式即可)
关于文档注释可参考:GoogleJavascriptGude
BOM和DOM简介
BOM
BOM就是浏览器提供给我们可以操作浏览器的API
我们常用的有:
打开新窗口,查看当前URL信息,检测浏览器类型和版本号,返回前一页,查询屏幕分辨率等
[参考]
/jsref/
《Javascript高级程序设计》第8章,第9章
DOM
DOM提供用于访问HTML/XML文档的API
浏览器之间有差异性,所以一般使用js类库来间接访问DOMAPI
有时候页面较简单,或者没有JS库引入,那可以直接使用
一般文档节点操作:/jsref/
样式/样式表处理(如旺铺DIY):《Javascript高级程序设计》10.3.2,11.2
jQuery学习
设计理念
//jQuery是一个function,返回一个对象(称为jQuery对象)
varjQuery=function(){
returnnewjQuery.fn.init(...);
};//jQuery对象的实例方法由jQuery.fn决定
jQtotype=jQuery.fn={...};
jQtotype=jQuery.fn;
//采用这种方法扩展jQuery
jQuery.fn.bind=function(){...};
//采用这种方法扩展静态方法
jQuery.extend=function(){...};
jQuery.each=function(){...};
所以jQuery包含两种操作:
一种是和DOM结点无关,直接调用静态方法即可,如$.ajax,$.each等
一种是和DOM结点相关,需要首先构造jQuery对象,再使用它的实例方法,如事件绑定jQuery#bind,样式设置jQuery#css等
Utility
<scriptsrc="></script"/js/lib/fdev-v4/core/fdev-min.js"></script>
(function($){//这里$就是jQuery})(jQuery);
$.ready初始化
domready后,表示可以使用js操作页面dom节点,它比onload要早,因为onload要等图片全部加载完
$.ready(function(){});//可以简写$(function(){
});
$.each迭代
vararray=['one','two','three'];
$.each(array,function(index,item){
//当item类型为object时,可使用this访问item,否则请使用参数方式访问item
});varo={name:...,value:...};
$.each(o,function(key,value){});
$.extend扩展//默认参数
functionhello(options){
options=$.extend({
title:'测试',
delay:1000
},options);
...
}//扩展功能
varA={
a:function(){}
};$.extend(A,{
b:function(){}
});
//clone
varo={...};varother=$.extend({},o);
我们可以扩展jQuery功能,但在应用中我们不允许这么做,维护fdevlib的同学可以根据需要扩展库$.extend({
add:function(){},
use:function(){}
});$.fn.extend({
tabs:function(){}
});
$.extendIf(由fdevlib实现),类似于extend,但如果存在相同key的项则不添加,我常常使用它来实现"继承"
varBase={
a:function(){
},b:function(){
},c:function(){}
};varA=$.extendIf({b:function(){},d:function(){}},Base);varBase=function(){
this.init.apply(this,arguments);
};
Btotype={};
varA=function(){
this.init.apply(this,arguments);
};
A.prototype=$.extendIf({},Btotype);
ajax
跨域jsonp请求$.ajax(url,{
dateType:'jsonp',
success:function(o){
o.success&&self.render(o.data);
}
});
浏览器会产生一次url类似url?callback=jQuery23522552_24342344的调用
期望浏览器返回这样的文本
jQuery23522552_24342344({"success":true,data:...})
此段代码将会作为js代码在客户端执行,即调用一个由jquery随机生成的方法,这个方法会调用我们的success方法,
于是我们就得到了数据
跨域调用要求使用jsonp方式,从避免造成全局名字空间污染和覆盖,也方便浏览器对数据进行垃圾回收
返回的数据格式要求如下:
{"success":true|false,data:...}
动态载入script文件$.ajax(url,{
dateType:'script',
success:function(){
//在这里script文件就载入完毕了
}
});
注,由于IE实现上的原因,造成造成script文件返回302也会进入success逻辑
所以如果如果采用古老的getscript方式来跨域请求数据的话,需要在success里进行判断.$.ajax(url,{
dateType:'script',
success:function(){
if(window.myData){
...
}
}
});//以上服务器反回这样的串串:varmyData=...
当然我们也可以使用这个方法发起xhr请求
$.ajax(url,{
type:'post',
data:{...}
success:function(html){
div.html(html);
}
});
注:在IE下,xhr请求,服务器如果返回302跳转(如另一页面退出后,旺铺DIY后台发起xhrpost请求,服务端会返回302),将会进入success逻辑
默认情况下,如果你ajax请求(包括xhr,jsonp,getScript),如果有参数data,并且类型为object,则jQuery使用
$.param来编码你的数据,内部会使用encodeURIComponent,这将导致中文编码成utf8.
如果后端木有按要求解码,这可能会产生问题.有两个解决方法:
1.前端不编码
自己使用$.paramSpecial--这个方法由fdev-v4提供,用于object->string,并且不编码,只转义几个uri中不允许的字符
2.要求后端解码(可能需要加参数input_charset参数),这一条优先采用
关于ajax或编辑相关的jqueryapi有:
$.param,$.paramSpecial,$.serialize,$.serializeArray
额外阅读:
关于跨域请求数据,除了使用getscriptjsonp还可以使用机制,work平台就使用了这个机制
具体请参考:/2008/09/01/window_name_transport/
关于script执行和浏览器渲染阻塞问题,请参看
《高性能网站建设进阶指南》第4章或《高性能Javascript》第一章
动态加载$.add,$.use
这两个方法由fdev-v4提供,使得我们可以按需加载组件
动态加载的方式使用我们的组件
$.use('web-alitalk',function(){
FE.util.alitalk($('a[data-alitalk]'));
});
在我们的应用中使用这种机制//在应用配置文件中注册
$.add('wp-dialog',{
js:['http://dialog.js']
});//在需要的地方使用
$.use('wp-dialog',function(){
newWP.widget.Dialog({
...
});
});
类型检测
根据我的经验,最有用的只有两个
$.isArray-判断是否为数组
$.isPlainObject-判断是否为"简单"对象if(typeofa==='string'){}if(typeofa==='function'){}if($.isArray(a)){}
$.trim
如果引入了fdev-min.js,则可以使用String#trimg()或$.trim()
如果仅仅使用jQuery,则可以使用$.trim(),因为有些浏览器(例IE6)没有实现trim方法
$.namespace
此方法由fdev-v4提供
namespace用于方便创建一个多层嵌套的对象结构用于代表名字空间(类似于java的package)
在应用中,我们不允许污染全局名字空间,一个应用往往只分配到一个名字空间
比如旺铺是Platform.winport,offer发布是在Platform.postoffer
那我们旺铺中的其他类都在这个名字空间下,初始化时会分配了如下几个名字空间
前后台都需要,在global/base.js中
jQspace(
'Platform.winport',
'Platform.winport.widget',//业务无关组件
'Platform.winport.unit'//TODO后续去掉mod.unit名字空间
'Platform.winport.mod',//板块
);
后台,在page/diy/diy.js中
jQspace(
'Platform.winport.diy',
'Platform.winport.diy.form'//板块编辑
);
注:上述为何有的文件在global中,有的文件在page/diy中,请参看style目录结构规划,
直接看文档/doc/page/regulations/dir-structure
$.proxyvarPage{init:function(config){
varself=this;this.config=config;$.use('ui-dialog',function(){
self.initDialog();
});
},initDialog:function(){
//assert(this===Page);node.dialog({
center:this.config.center
});
}
};//使用proxyvarPage={init:function(){
$.use('ui-dialog',$.proxy(this,'initDialog'));
},initDialog:function(){}
};
下面这样写达不到目的
varPage={
init:function(config){
this.config=this.config;$.use('ui-dialog',this.initDialog);
},initDialog:functoin(){
assert(this!==Page);this.config//undefined
}
};
所以proxy用于方便创建一个代理function,让被代理的function具有指定的context
1.6版本的proxy还可以包装额外的参数,但文档还没有更新,具体可参看源码1.6.2第804行
提外话:
一个看源码技巧:在页面中引入jquery非压缩版.
在firebugscripttab的watch中输入jQuery,展开对象找到相应的方法单击即可看到相应的源码varPage={init:function(){
vararg1='arg1',
arg2='arg2';$.ajax(url,{
dateType:'jsonp',
success:$.proxy(this,'ajaxSuccess',arg1,arg2);
});
},ajaxSuccess:function(arg1,arg2,ret){
assert(this===Page);
assert(arg1==='arg1');
assert(arg2==='arg2');if(ret.success){
...
}
}};
为了提高JS代码可读性,我曾做过分享,其中有一条是:
一个功能性方法,代码行数不超过40行(正常情况下会在一屏之内)
如果要达到上述要求,方法里面将不可能包含很深的嵌套,即代码嵌套层次不超过3
如:
varPage={
initPartA:function(){
varself=this;//level1
$.ajax(url,{
dateType:'jsonp',
//level2
success:function(ret){
//level3
ret.success&&self.render(ret.data);
};
});
},render:function(data){}
};
其他常用方法
$.map,$.makeArray
functiontest(){
varargs=$.makeArray(arguments);
}//参数可以是数组或非数组
functiontest(args){
args=$.makeArray(args);
}
$.map相当于CollectionUtils.transform
varlinks=$('a'),
urls=null;urls=$.map(links,function(index,link){
return$(link).attr('href');
});
选择与CSS3选择器
认识选择器
简单选择器(simpleselecotr)
$('*');//universalselector星号选择器选择所有节点$('div');//typeselector/elementselector类型选择器(我习惯叫它tag选择器)$('#header');//idselectorid选择器$('.input-text');//classselectorclass选择器$(':input');//pseudoselector伪类选择器选择所有表单输入域
//a:hover,a:linked,a:visited两个冒号带头的就是伪类选择器
$('li:first')//选择第一个li节点$('[name="alibaba"]')//attributeselector属性选择器选择所有name属性=alibaba的节点
$('[name]')//存在...
combinator~~~js
$('#headera')//descendantselector后代选择器
$('#headerulli')$('#header>div')//childselector子代选择器
//下面两个邻代选择器应该不常用,我从来没有用过
$(':input+span')//nextadjacentselector在input后面的,紧挨着的那个span
$(':input~span')//nextsiblingselector在input后面的,所有同代span
$('div,a,:input')//multipleSelector
$('a.close:acitve')//and
使用选择器
尽量使用简单的选择器,如
$('#id')
$('a.close',container)//class需要带tag限制,
//由于在ie6等浏览器对class没有原生api支持,使得单纯的classselector比较慢
$('ul>li',container)//有context限制
优先级
非常简单,一句话:
id>非(id,tag)>tag,相同等级看数量
参看/TR/css3-selectors/第9节
[额外阅读]
CSS3选择器详细内容请参考W3C文档:/TR/css3-selectors/
jQuery支持的选择器请参考:/category/selectors/
构造jQuery对象
//from选择器
$('#publish-dialoga.close');
//fromdom节点
vardom=$('#doc')[0];
$(dom);
//fromjquery对象
varchooser=$('div.offer-chooser');
varpanel=chooser.find('ul.chooser-panel');
或者
varpanel=$('ul.chooser-panel',chooser);//内部调用find来完成
jquery对象结构
如果针对本文档,在firefoxscriptwatch中输入jQuery('ul'),将创建一个jQuery对象,
用于操作文档中所有ul节点,展开它会看到如下对象结构
{
0:ul,//HTMLUListElement,即原生dom节点对象
1:ul,
2:ul,
...
7:ul,length:8,selector:'ul',
context:document,
prevObject:document
...
}
jQuery对象是一个普通对象,有数组相似的接口,所以可以像数组一样参于迭代
构造一个jQuery对象成本不大,因为只包含一些引用字段,没有大数据字段
了解这个是为了让我们更好地使用jQuery,而不是把$(美元符号)当作一种奇怪的语法来用.
见下面这段jQuery初学者常见的代码
$('a.close',div).click(function(){
$(this).addClass('abc');
if(...){
$(this).attr(...)
}else{
$(this).data(...);
}$(this)...
});
为了增加可读性,提高效率和减少不必要的内存消耗,请记住$(elm)等于newjQuery(elm);
只构造必要的jQuery对象,上述代码可以这么写
elms.click(function(){
varelm=$(this);//保存引用
...
});
基本操作
varlis=$('ul.offer-listli');
if(!lislength){//判断节点是否存在
return;
}lis.eq(0).addClass('first');//只对第一个节点处理,相当于$(lis[0]).addClass('first');varfirstLi=lis[0];//取得第1个节点(htmldom元素)
lis.each(function(index){
varli=$(this);//each中的this是原生的dom对象
li.data('offer',offers[index]);
});
事件
普通事件$('a.open',panel).click(function(e){
e.preventDefault();newDialog({
header:'设置'
width:'700',
height:'350',
confirm:function(){
...
}
});
});
上述事件挂接,也可以使用bind
button.bind('click',function(e){
...
});
click方法只是bind方法的一个包装,相似的还有其他事件:change,resize,dblclick,keypress等
几乎所有常用的浏览器事件都有直接对应的方法用于挂接或触发事件
关于其他事件请参考:/category/events/
关于事件函数有几点说明:
关于this
this指向触发事件的元素(htmldom节点)
$('a.delete',list).click(function(e){
e.prevent();varlink=$(this),//here,isahtmlelement
li=link.closest('li'),postId=li.data('postId');Post.delete(postId);
});
关于参数event
我们可以从中获取一些关于事件的参数,如鼠标位置,键盘输入等等,
或者取消浏览器默认事件,阻止冒泡
$('a.close',dialog).click(function(e){
e.preventDefault();//阻止链接正常行为,
//因为这个链接是作为功能按扭来使用的,而不需要跳转或重新定位瞄点
...
});
$('div.canvas').mousemove(function(e){
varx=e.pageX,//鼠标位置
y=e.pageY;});$('input.username').keydown(function(e){
varself=this;if(e.keyCode===13){//回车
self.submitForm();
}
});
关于eventobject请参考:/category/events/event-object/
触发事件
有时候需要人为地触发一个浏览器事件,如提交表单
或者打开浮层登录框框后需要默认选择第二个tab,就相当于"按"一下那个tab
form.submit();
tabs.eq(2).click();
或者
form.trigger('submit');
tabs.eq(2).trigger('click');
同bind,无参数的click或submit只是trigger的一个包装
trigger它会执行浏览器默认行为,比如当你click一个checkbox的时候,界面中的checkbox也会勾选或取消勾选
同时trigger还会冒泡(关于事件冒泡,下面会有)
如果只想执行事件,而不触发默认行为,请使用triggerHandler
同时trigger和triggerHandler还支持额外的参数,具体可参考文档
/trigger/
/triggerHandler/
事件冒泡
body
div#doc
div#header
div.search-bar
input.search-btn[type=button]
当我们点击input.search-btn时,input.search-btn,div.search-bar,div.#header,div#doc,body依次会触发click事件.
这个过程叫事件冒泡
关于事件冒泡更细致的内容可参考:/category/events/
所以如果我们所事件函数挂接在外围节点,将能接收到里面子节点的事件.
容器内部节点动态创建的事件绑定
div.click(function(e){
if($(e.target).is('a.delete')){
//..
}
});以上代码可以这样写:div.delegate('a.delete','click',function(){});
如果有很多个节点需要绑定事件,此时可以使用冒泡绑定在外围容器上,很大地提高效率//bigtable为大表格
$('table.bigtabletd').dblclick(function(){
});//请使用事件代理绑定事件
$('table.bigtable').delegate('td','dblclick',function(){});
自定义事件
//move.js
saveLayout:function(){
...
$('window').trigger('diychanged',{type:'layout'});
}//diy-skins
saveSkin:function(){
$('window').trigger('diychanged',{type:'diyskins'});
}
//header.js
showTips:function(){
$('window').bind('diychanged',function(e,data){
newTips({
//...
message:'点击发布可应用您的修改到旺铺'
});
});
}
namespace事件
$('a.mylink').bind('click',function(){});$('a.mylink').bind('click.mylink',function(){});//移除事件
$('a.mylink').unbind('click.mylink');
//触发指定namespace事件
$('a.mylink').triggerHandler('click.mylink');
关于namespace的参考链接,官网上我一时找不到了,不好意思,以前记得有的,现在只有一点点:
/bind/
/unbind/
或者直接参看源码可能会更清晰:jquery1.6.2,第2619行,第2726行,第2810行
操作
节点操作的api可直接参考/category/manipulation/
有几点需要说明,dom节点操作是所有操作里最慢的,往往页面的效率瓶颈就在dom操作,所以要特别注意
改变属性的操作如:addClass,removeClass,css等需要浏览器重绘节点
而html,append,prepand,等节点操作需要浏览器重排节点并且重绘
具体请参考:《HighPerformanceJavascript》chapter3
可以像这样:
render:function(offers){
varself=this,
html=[];$.each(offers,function(index,offer){
html.push(self.createItemHtml(offer));
});div.html('<ul>'+html.join('')+'</ul>');
}或者render:function(offers){
varself=this,
ul=$('<ul>');$.each(offers,function(index,offer){
ul.appen
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025企业间借款合同模板:公司与公司借款协议
- 员工职业发展路径计划
- 居民健康教育活动计划
- 校外生物考察活动安排计划
- 2025版借款合同范本2
- 供应商管理对生产计划的影响
- 2025年度其他贸易合同 西瓜产销合同
- 2025房产租赁合同协议书
- 自我评估与职业目标的调整计划
- 2025汽车购销合同补充协议书
- GB/T 8411.3-2009陶瓷和玻璃绝缘材料第3部分:材料性能
- GB/T 4857.17-2017包装运输包装件基本试验第17部分:编制性能试验大纲的通用规则
- “两区三厂”专项施工方案
- 汽车消声器设计课件
- 调试报告-交换机
- 屋面防水施工技术PPT (2020,44P)
- 铁路隧道出口支护、仰拱、防排水首件评估监理总结
- 关于无行贿犯罪行为记录的承诺书
- 防城港职业技术学院筹设实施方案
- 城市雕塑艺术工程量清单计价定额2020版
- 淘汰赛赛对阵表
评论
0/150
提交评论