js語法、語義函數(shù)_第1頁
js語法、語義函數(shù)_第2頁
js語法、語義函數(shù)_第3頁
js語法、語義函數(shù)_第4頁
js語法、語義函數(shù)_第5頁
已閱讀5頁,還剩27頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

語法和語義

可選的分號

標(biāo)識符(Identifier)

基礎(chǔ)數(shù)據(jù)類型和字面量(Literal)

變量的作用域

關(guān)于==,!=,===,!==

關(guān)于this,new,apply,call

關(guān)于arguments

成員訪問,prototype鏈,繼承

變量訪問,callobject,Closure

總結(jié)

慣用法和技巧

編碼規(guī)范和JS書寫模板

頁面功能的普通功能

模塊需要提供給其他模塊使用(單例)

模塊需要提供給其他模塊使用(多實(shí)例)

為繼承而設(shè)計(jì)的類

繼承其他類

BOM和DOM簡介

BOM

DOM

jQuery學(xué)習(xí)

設(shè)計(jì)理念

Utility

選擇與CSS3選擇器

構(gòu)造jQuery對象

jquery對象結(jié)構(gòu)

基本操作

事件

操作

數(shù)據(jù)

檢測

前端基礎(chǔ)庫fdevlib

style目錄結(jié)構(gòu)簡要說明

fdev-v4現(xiàn)有組件

JS學(xué)習(xí)

本文目的在于為Java或有語言基礎(chǔ)的同學(xué)參于前端開發(fā)提供指導(dǎo)

語法和語義

可選的分號

語句如果它們在單獨(dú)一行,那么結(jié)尾的分號可以省略。

注:為了一致性和避免錯誤(如壓縮或merge帶來的錯誤),我們要求所有語句都要加分號(塊語句和函數(shù)申明語句后不需要分號)

vara=1;

a+=1;varcallback=function(){

return'hi';

};//函數(shù)申明語句

functionother(){}for(vari=0;i<10;i++){}if(a===123){}

[注]我們不能寫出這樣的句子

functionabc(){

return//返回123

123;

}

abc();//->undefined

標(biāo)識符(Identifier)

和Java相比,Javascript允許在標(biāo)識符中使用$,所以很多庫都用它來定義特殊作用的全局對象

像jQuery,Prototype,Mootools等框架使用$操作頁面節(jié)點(diǎn),它僅是一個普通的函數(shù)

//在jQuery中

$('#mydiva').css('color','#f00');//設(shè)置鏈接顏色//在舊版本的Mootools中

if($type(abc)==='string'){//新版本使用typeOf代替}//在中文站JS基礎(chǔ)庫FDEV3中

varelm=$('mydiv');//相當(dāng)于document.getElementById('mydiv');

所以$可以用作有"特殊"含義的變量名

//在有些同學(xué)的代碼中,用于在內(nèi)部函數(shù)中訪問外圍對象

varTest={hi:function(){

var$this=this;//我見過的常用的名稱還有that,self,me等,

//使用self有一個隱患,就是忘記了定義self時,

//會造成難以排錯,因?yàn)橛幸粋€全局的self會產(chǎn)生干憂$.ajax(url,{

success:function(o){

o.success&&$this.render(o.data)

}

});

},render:function(){}

};

基礎(chǔ)數(shù)據(jù)類型和字面量(Literal)

Number

123,0xf000,0377(8進(jìn)制)

3.14,.222,1.2e12,1.4e-12

可以使用Math對象進(jìn)行常見的科學(xué)計(jì)算,見/js/js_obj_math.asp

此外Javascript也定義了一些特殊的Number用于合適的需要,如NaN,Number.MAX_VALUE,Number.MIN_VALUE,

參考《Javascript權(quán)威指頁》3.1.6

注:當(dāng)使用parseInt將字符串轉(zhuǎn)成整型時,請帶上進(jìn)制,否則如果有前綴是0,會被當(dāng)成8進(jìn)制處理可能不符合預(yù)期需求

varnum=parseInt(inputText,10);//如在文本框輸入頁碼等

String

可以使用單引號或雙引號兩種形式varstr1='我是一個字符串,包含著雙引號"';//單引號中的雙引號可以不用轉(zhuǎn)義,當(dāng)然使用轉(zhuǎn)義也木有問題varstr2="我是另一個字符串,包含著單引號'";

vartemplate=

'<div>\

<dl>\

<dt>示例1</dt>\

<dd></dd>\

<dt></dt>\

<dd></dd>\

</dl>\

</div>';

String和Number的轉(zhuǎn)化技巧

parseInt('123',10);//注:請加上第二個參數(shù)'123'-0//注:不能使用+456+''

123456+'元'//->'123456元';

[String對象的方法請參考]

/jsref/jsref_obj_string.asp

Boolean

false,null,undefined,0,NaN,''在邏輯判斷中都被當(dāng)成false處理

varkeyword=$('#keyword').val();

if(!$.trim(keyword)){

//用戶輸入為空

}varnum=$('#num').val();

num=parseInt(num,10);if(!num){//NaN

//用戶輸入非法數(shù)字

}

Function

//申明式

functiona(){}

console.debug()//->'a'

//匿名函數(shù)

varb=function(){};

console.debug()//->''

申明式和語句式區(qū)別

fun(123);//在這里就可以使用functionfun(value){

console.debug(value);

}

b(123);//bisundefined;varb=function(){

};

ObjectLiteral

varalbum={

name:'pipixiuxiu',//注,這里的name不是變量,只是省略了單引號

‘count’:100,'private':true,//當(dāng)屬性名稱是保留字時,必須使用這種方式234:'較少用',

12.34:'更少用'

};;

album['count'];album[234];

jQuery對象是怎么造就的?

varo={

0:elm0,

1:elm1,

2:elm2,

3:elm3,length:4,

splice:function(){}//firebug看到這個會以為它是個數(shù)組,所以顯示方式和數(shù)組一樣

...

}

注:使用Literal語法構(gòu)造對象,而不是newObject()

varo={};//而不是newObject();

ArrayLiteral

varary=[];

ary[0]='one';

varlist=[99,'somestring',function(){}];

[Array的方法請參考]

/jsref/jsref_obj_array.asp

注:**總是使用Literal語法構(gòu)造數(shù)組,而不是使用newArray()**

vararray=[];//而不是newArray();

拼接字符串,在Java中使用StringBuilder或StringBuffer拼接字符串,以減少臨時對象的產(chǎn)生提高GC效率。

在JS中使用數(shù)據(jù)組達(dá)到這一目的。

varhtml=[];elms.each(function(){

html.push('somestring...');

});html=html.join('');

[注]在Object/Array最后一個元素后面不能加逗號,盡管這在標(biāo)準(zhǔn)上允許,但是在IE67瀏覽器下會報語法錯誤

所以,如果發(fā)現(xiàn)在FF下工作正常,在IE下工作不正常,請檢查是否object或array最后多了個逗號

varo={

name:'pipi',

desc:'ererer',

//price:12//在調(diào)試中把這句注釋了,造成上面一句最后多了個逗號

};

所以可能在某些代碼中發(fā)現(xiàn)以下寫法以避免上述錯誤

varo={

name:'pipi',

desc:'ererer',

//price:12,

_:0//多了一個這樣的元素

};

不過我不推薦這樣的形式,注意點(diǎn)就好,因?yàn)樯鲜鲂问娇赡軙砥渌[患,并且可讀性也不好。

可以借助工具來掃描這類錯誤,如JSLint:/

變量的作用域

變量在JS中是函數(shù)作用域的,而不是塊作用域(C,Java,C#等是塊作用域)

functionhello(){

vara=123;for(vari=0;i<10;i++){

vara=234;

//...

}console.debug(a);//->234

}

在函數(shù)作用域內(nèi)定義的var都相當(dāng)于在一開始定義一樣

即一個函數(shù)執(zhí)行時,引擎分兩步操作

1.處理所有var語句(和函數(shù)申明語句),準(zhǔn)備好執(zhí)行環(huán)境,相當(dāng)于這些var和function申明語句寫在函數(shù)的最前面

2.執(zhí)行函數(shù)內(nèi)的語句

所以上述代碼相當(dāng)于這樣:

functionhello(){

vara,

i;a=123;for(i=0;i<10;i++){

a=234;

//...

}console.debug(a);//->234

}

這會讓javascript虛擬機(jī)實(shí)現(xiàn)closure更方便,讓內(nèi)存模型更簡潔

functionhello(){

alert(a);//alert(undefined);if(false){

vara;

}

}等效于functionhello(){

vara;alert(a);if(false){

}

}

functionhello(){

alert(a);//ReferenceError:aisnotdefined

}

[最佳實(shí)踐]

一個函數(shù)內(nèi)最好只有一個var,并且盡可能靠前(最好是在函數(shù)一開始)但這與塊作用域的實(shí)踐,變量最好在用到的時候定義不一致

所以函數(shù)盡可能得短小,以滿足前面兩個條件

關(guān)于==,!=,===,!==

一句話:總是使用===和!==進(jìn)行比較

因?yàn)?=和!=在比較時如有必要,會進(jìn)行類型轉(zhuǎn)換

null==undefined//->true

'0'==false//->true

'1'==true//->truenull==false//->false

undefined==false//->false

[具體的比較規(guī)則請參考]ECMA26211.9.3

如果不想看,可能參考一條規(guī)則:null==undefined,字符串和boolean都轉(zhuǎn)成數(shù)字進(jìn)行比較

關(guān)于this,new,apply,call

當(dāng)調(diào)用一個方法(函數(shù)時),函數(shù)內(nèi)部的this指向一個對象,在規(guī)范中被稱為:ThisBinding,我喜歡叫它BindObject

一般情況下,this指向調(diào)用它的那個對象或者GlobalObject,在瀏覽器中為window

varA={

hello:function(){

console.debug(this);

}

};A.hello();//->Avarb=A.hello;

b();//->GlobalObject,在瀏覽器中即是window

所以函數(shù)中的this指向和如何調(diào)用它有關(guān)系,和在哪里定義這個函數(shù)關(guān)系不大

我們可以使用call或apply方法參數(shù)化this

varA={

name:'A',functionhello(){

console.debug(this.anme);

}

};A.hello();//this===A

varB={name:'B'};A.hello.call(B);//this===B

至于call和apply的區(qū)別,只是方法支持參數(shù)的區(qū)別,功能一樣

fun.apply(o,[arg1,arg2,arg3]);function.call(o,arg1,arg2,arg3);

new操作符會構(gòu)造一個對象,并且讓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面向?qū)ο蟮挠白?/p>

關(guān)于new的返回值

如果function返回object,則new返回那個object,否則返回引擎構(gòu)造的那個objectfunctionA(){}

newA();//->object

functionB(){

varo={};

returno;

}

newB();//->o

functionC(){

return1;//typeof1==='number',1isnotanobject

}

newC();//->object,not1

關(guān)于arguments

函數(shù)內(nèi)部除this外,還有一個對象就是arguments,它是一個類數(shù)組,保存著函數(shù)的調(diào)用參數(shù)

functiona(){

varargs=arguments,

a=args[0],

b=args[3],

len=args.length;

}

我們可以對arguments進(jìn)行迭代,但如果我們要使用數(shù)組的方法操作它,就需要把它轉(zhuǎn)化成數(shù)組

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'

//設(shè)置

='o';

;//'o'//找到了,就不需要訪問prototype了

o.hello();//'helloo'//A未曾改變

A.name//'A'

A.hello//'helloA'

讀取一個對象成員時,會走prototype鏈,設(shè)置一個對象成員時,對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對象來實(shí)現(xiàn)類,以及用prototype鏈來實(shí)現(xiàn)繼承

我們使用如下模板書寫一個簡單的類varA=function(){

this.init.apply(this,arguments);//代理給prototype.init

};

A.prototype={/**

*構(gòu)造函數(shù)

*/

init:function(name){

=name;//對象屬性

},/**

*實(shí)例方法

*/

hello:function(){

console.debug('hello'+);

}

};

JS是動態(tài)的語言,可以很方面地實(shí)現(xiàn)對象的功能擴(kuò)展,所以比較少用繼承

如果使用繼承,我會使用以下方法來實(shí)現(xiàn),因?yàn)榇a較原型鏈方式來得更簡單

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中,變量是函數(shù)作用域的,這一點(diǎn)上面已講過

這里的訪問主要考慮嵌套函數(shù)的調(diào)用,即一個非常重要的特性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');

每次調(diào)用一個函數(shù)時,執(zhí)行函數(shù)代碼前,Js執(zhí)行引擎要做些準(zhǔn)備工作,其中會創(chuàng)建一個稱為CallObject的對象

而調(diào)用方法的形式參數(shù),局部變量,arguments等就成為這個對象的屬性.

所以訪問形式參數(shù),局部變量,arguments就相當(dāng)于訪問這個對象的屬性總結(jié)

JS的語言本身非常精簡,整個ECMA262規(guī)范只有200頁,其中有一半用來介紹了核心庫的內(nèi)容,

語言語法,語義,引擎的實(shí)現(xiàn)全部加起來也才100頁.所以真的是非常地精巧,但描述能力卻很強(qiáng)大.

引擎核心內(nèi)容總結(jié)如下:

this會動態(tài)地指向BindObject,所以又稱為動態(tài)作用域.我們對this屬性的訪問就是訪問這個對象的屬性.

變量的訪問,其實(shí)是訪問的是CallObject的屬性,CallObject鏈根據(jù)詞法結(jié)構(gòu)就已確定,所以又稱為靜態(tài)作用域,或“詞法作用域”

由于這個鏈在js中是不能訪問的,所以又稱"暗鏈"

對象屬性(成員)的訪問,遵循的是prototype鏈,由于這個鏈在js中是可以直接訪問的,所以又稱為"明鏈"

[如果對上述內(nèi)容詳細(xì)內(nèi)容感興趣可以參看]

*《Javascript權(quán)威指》:4.64.7

*ECMA26210.3~10.6

*/faq/notes/closures/

*我的文章:/pages/viewpage.action?pageId=47748204

慣用法和技巧

//檢測空串

if(!$.trim(str)){}//字符串/數(shù)字類型轉(zhuǎn)換

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;賦值運(yùn)算附優(yōu)先級低

可以是options.delay&&(this.delay=true);

//默認(rèn)參數(shù)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>';

編碼規(guī)范和JS書寫模板

JS是一門動態(tài)靈活的語言,不同的同學(xué)可能寫出風(fēng)格完全不同的代碼.

所以參考或使用此模板目的在于提高js代碼一致性和可讀性.

首先需要參考:前端CodeReview列表

頁面功能的普通功能

如Diy皮膚功能,Js文件名為diy-skins.js

我們把文件中模塊代碼包含在一個自執(zhí)行匿名函數(shù)中,以避免全局名字空間沖突

原則上一個文件只包含一個模塊(一般是一個主類)

因?yàn)槲覀兊膍erge腳本不夠強(qiáng),為了按需加載和減少請求數(shù),有可能會把一個組件所有代碼放在一個文件中

但是也需要把每個模塊放在各自的自執(zhí)行匿名函數(shù)中

/**

*旺鋪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(...)//相當(dāng)于//頁面載入后就執(zhí)行

$(function(){

Diy.Skin.init();

})})(jQuery,Platform.winport);

[1].這個區(qū)域相當(dāng)于java的import區(qū),根據(jù)需要可以alias一些用到的類

當(dāng)然現(xiàn)在我們還需要在merge文件中包含需要的庫文件.

后續(xù)我們會期望引入腳本來自動merge導(dǎo)入的類

像這樣:

varUtil=require('widget/util'),

UI=require('widget/ui'),

ModBox=require('diy/mod-box');

[2].主模塊(類/對象)名要求和js文件名盡量保持一致

[3].初始化方法或構(gòu)造函數(shù)名稱為init

[4].最后當(dāng)頁面domready時應(yīng)該執(zhí)行初始化方法,所以調(diào)用jquery.ready方法(在旺鋪中進(jìn)行一些封裝,所以調(diào)用PageContext.register進(jìn)入注冊)

模塊需要提供給其他模塊使用(單例)

(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);

相當(dāng)于方法,可由其他模塊調(diào)用

下劃線帶頭的方法,不可由其他模塊調(diào)用

掛接到相應(yīng)的名字空間下,以便由外界可以使用

模塊需要提供給其他模塊使用(多實(shí)例)

(function($,WP){

varTabs=function(){

this.init.apply(this,arguments);

};Ttotype={init:function(tabs,bodies){},_create:function(){}

};WP.widget.Tabs=Tabs;

})(jQuery,Platform.winport);

為繼承而設(shè)計(jì)的類

(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].構(gòu)造函數(shù)

[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].調(diào)用父類構(gòu)造函數(shù)

[2].重寫父類方法,調(diào)用父類方法

[3].private方法

[4].public方法

[5].private(和3選擇一種形式即可)

關(guān)于文檔注釋可參考:GoogleJavascriptGude

BOM和DOM簡介

BOM

BOM就是瀏覽器提供給我們可以操作瀏覽器的API

我們常用的有:

打開新窗口,查看當(dāng)前URL信息,檢測瀏覽器類型和版本號,返回前一頁,查詢屏幕分辨率等

[參考]

/jsref/

《Javascript高級程序設(shè)計(jì)》第8章,第9章

DOM

DOM提供用于訪問HTML/XML文檔的API

瀏覽器之間有差異性,所以一般使用js類庫來間接訪問DOMAPI

有時候頁面較簡單,或者沒有JS庫引入,那可以直接使用

一般文檔節(jié)點(diǎn)操作:/jsref/

樣式/樣式表處理(如旺鋪DIY):《Javascript高級程序設(shè)計(jì)》10.3.2,11.2

jQuery學(xué)習(xí)

設(shè)計(jì)理念

//jQuery是一個function,返回一個對象(稱為jQuery對象)

varjQuery=function(){

returnnewjQuery.fn.init(...);

};//jQuery對象的實(shí)例方法由jQuery.fn決定

jQtotype=jQuery.fn={...};

jQtotype=jQuery.fn;

//采用這種方法擴(kuò)展jQuery

jQuery.fn.bind=function(){...};

//采用這種方法擴(kuò)展靜態(tài)方法

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

jQuery.each=function(){...};

所以jQuery包含兩種操作:

一種是和DOM結(jié)點(diǎn)無關(guān),直接調(diào)用靜態(tài)方法即可,如$.ajax,$.each等

一種是和DOM結(jié)點(diǎn)相關(guān),需要首先構(gòu)造jQuery對象,再使用它的實(shí)例方法,如事件綁定jQuery#bind,樣式設(shè)置jQuery#css等

Utility

<scriptsrc="></script"/js/lib/fdev-v4/core/fdev-min.js"></script>

(function($){//這里$就是jQuery})(jQuery);

$.ready初始化

domready后,表示可以使用js操作頁面dom節(jié)點(diǎn),它比onload要早,因?yàn)閛nload要等圖片全部加載完

$.ready(function(){});//可以簡寫$(function(){

});

$.each迭代

vararray=['one','two','three'];

$.each(array,function(index,item){

//當(dāng)item類型為object時,可使用this訪問item,否則請使用參數(shù)方式訪問item

});varo={name:...,value:...};

$.each(o,function(key,value){});

$.extend擴(kuò)展//默認(rèn)參數(shù)

functionhello(options){

options=$.extend({

title:'測試',

delay:1000

},options);

...

}//擴(kuò)展功能

varA={

a:function(){}

};$.extend(A,{

b:function(){}

});

//clone

varo={...};varother=$.extend({},o);

我們可以擴(kuò)展jQuery功能,但在應(yīng)用中我們不允許這么做,維護(hù)fdevlib的同學(xué)可以根據(jù)需要擴(kuò)展庫$.extend({

add:function(){},

use:function(){}

});$.fn.extend({

tabs:function(){}

});

$.extendIf(由fdevlib實(shí)現(xiàn)),類似于extend,但如果存在相同key的項(xiàng)則不添加,我常常使用它來實(shí)現(xiàn)"繼承"

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);

}

});

瀏覽器會產(chǎn)生一次url類似url?callback=jQuery23522552_24342344的調(diào)用

期望瀏覽器返回這樣的文本

jQuery23522552_24342344({"success":true,data:...})

此段代碼將會作為js代碼在客戶端執(zhí)行,即調(diào)用一個由jquery隨機(jī)生成的方法,這個方法會調(diào)用我們的success方法,

于是我們就得到了數(shù)據(jù)

跨域調(diào)用要求使用jsonp方式,從避免造成全局名字空間污染和覆蓋,也方便瀏覽器對數(shù)據(jù)進(jìn)行垃圾回收

返回的數(shù)據(jù)格式要求如下:

{"success":true|false,data:...}

動態(tài)載入script文件$.ajax(url,{

dateType:'script',

success:function(){

//在這里script文件就載入完畢了

}

});

注,由于IE實(shí)現(xiàn)上的原因,造成造成script文件返回302也會進(jìn)入success邏輯

所以如果如果采用古老的getscript方式來跨域請求數(shù)據(jù)的話,需要在success里進(jìn)行判斷.$.ajax(url,{

dateType:'script',

success:function(){

if(window.myData){

...

}

}

});//以上服務(wù)器反回這樣的串串:varmyData=...

當(dāng)然我們也可以使用這個方法發(fā)起xhr請求

$.ajax(url,{

type:'post',

data:{...}

success:function(html){

div.html(html);

}

});

注:在IE下,xhr請求,服務(wù)器如果返回302跳轉(zhuǎn)(如另一頁面退出后,旺鋪DIY后臺發(fā)起xhrpost請求,服務(wù)端會返回302),將會進(jìn)入success邏輯

默認(rèn)情況下,如果你ajax請求(包括xhr,jsonp,getScript),如果有參數(shù)data,并且類型為object,則jQuery使用

$.param來編碼你的數(shù)據(jù),內(nèi)部會使用encodeURIComponent,這將導(dǎo)致中文編碼成utf8.

如果后端木有按要求解碼,這可能會產(chǎn)生問題.有兩個解決方法:

1.前端不編碼

自己使用$.paramSpecial--這個方法由fdev-v4提供,用于object->string,并且不編碼,只轉(zhuǎn)義幾個uri中不允許的字符

2.要求后端解碼(可能需要加參數(shù)input_charset參數(shù)),這一條優(yōu)先采用

關(guān)于ajax或編輯相關(guān)的jqueryapi有:

$.param,$.paramSpecial,$.serialize,$.serializeArray

額外閱讀:

關(guān)于跨域請求數(shù)據(jù),除了使用getscriptjsonp還可以使用機(jī)制,work平臺就使用了這個機(jī)制

具體請參考:/2008/09/01/window_name_transport/

關(guān)于script執(zhí)行和瀏覽器渲染阻塞問題,請參看

《高性能網(wǎng)站建設(shè)進(jìn)階指南》第4章或《高性能Javascript》第一章

動態(tài)加載$.add,$.use

這兩個方法由fdev-v4提供,使得我們可以按需加載組件

動態(tài)加載的方式使用我們的組件

$.use('web-alitalk',function(){

FE.util.alitalk($('a[data-alitalk]'));

});

在我們的應(yīng)用中使用這種機(jī)制//在應(yīng)用配置文件中注冊

$.add('wp-dialog',{

js:['http://dialog.js']

});//在需要的地方使用

$.use('wp-dialog',function(){

newWP.widget.Dialog({

...

});

});

類型檢測

根據(jù)我的經(jīng)驗(yàn),最有用的只有兩個

$.isArray-判斷是否為數(shù)組

$.isPlainObject-判斷是否為"簡單"對象if(typeofa==='string'){}if(typeofa==='function'){}if($.isArray(a)){}

$.trim

如果引入了fdev-min.js,則可以使用String#trimg()或$.trim()

如果僅僅使用jQuery,則可以使用$.trim(),因?yàn)橛行g覽器(例IE6)沒有實(shí)現(xiàn)trim方法

$.namespace

此方法由fdev-v4提供

namespace用于方便創(chuàng)建一個多層嵌套的對象結(jié)構(gòu)用于代表名字空間(類似于java的package)

在應(yīng)用中,我們不允許污染全局名字空間,一個應(yīng)用往往只分配到一個名字空間

比如旺鋪是Platform.winport,offer發(fā)布是在Platform.postoffer

那我們旺鋪中的其他類都在這個名字空間下,初始化時會分配了如下幾個名字空間

前后臺都需要,在global/base.js中

jQspace(

'Platform.winport',

'Platform.winport.widget',//業(yè)務(wù)無關(guān)組件

'Platform.winport.unit'//TODO后續(xù)去掉mod.unit名字空間

'Platform.winport.mod',//板塊

);

后臺,在page/diy/diy.js中

jQspace(

'Platform.winport.diy',

'Platform.winport.diy.form'//板塊編輯

);

注:上述為何有的文件在global中,有的文件在page/diy中,請參看style目錄結(jié)構(gòu)規(guī)劃,

直接看文檔/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(){}

};

下面這樣寫達(dá)不到目的

varPage={

init:function(config){

this.config=this.config;$.use('ui-dialog',this.initDialog);

},initDialog:functoin(){

assert(this!==Page);this.config//undefined

}

};

所以proxy用于方便創(chuàng)建一個代理function,讓被代理的function具有指定的context

1.6版本的proxy還可以包裝額外的參數(shù),但文檔還沒有更新,具體可參看源碼1.6.2第804行

提外話:

一個看源碼技巧:在頁面中引入jquery非壓縮版.

在firebugscripttab的watch中輸入jQuery,展開對象找到相應(yīng)的方法單擊即可看到相應(yīng)的源碼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代碼可讀性,我曾做過分享,其中有一條是:

一個功能性方法,代碼行數(shù)不超過40行(正常情況下會在一屏之內(nèi))

如果要達(dá)到上述要求,方法里面將不可能包含很深的嵌套,即代碼嵌套層次不超過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);

}//參數(shù)可以是數(shù)組或非數(shù)組

functiontest(args){

args=$.makeArray(args);

}

$.map相當(dāng)于CollectionUtils.transform

varlinks=$('a'),

urls=null;urls=$.map(links,function(index,link){

return$(link).attr('href');

});

選擇與CSS3選擇器

認(rèn)識選擇器

簡單選擇器(simpleselecotr)

$('*');//universalselector星號選擇器選擇所有節(jié)點(diǎn)$('div');//typeselector/elementselector類型選擇器(我習(xí)慣叫它tag選擇器)$('#header');//idselectorid選擇器$('.input-text');//classselectorclass選擇器$(':input');//pseudoselector偽類選擇器選擇所有表單輸入域

//a:hover,a:linked,a:visited兩個冒號帶頭的就是偽類選擇器

$('li:first')//選擇第一個li節(jié)點(diǎn)$('[name="alibaba"]')//attributeselector屬性選擇器選擇所有name屬性=alibaba的節(jié)點(diǎn)

$('[name]')//存在...

combinator~~~js

$('#headera')//descendantselector后代選擇器

$('#headerulli')$('#header>div')//childselector子代選擇器

//下面兩個鄰代選擇器應(yīng)該不常用,我從來沒有用過

$(':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限制

優(yōu)先級

非常簡單,一句話:

id>非(id,tag)>tag,相同等級看數(shù)量

參看/TR/css3-selectors/第9節(jié)

[額外閱讀]

CSS3選擇器詳細(xì)內(nèi)容請參考W3C文檔:/TR/css3-selectors/

jQuery支持的選擇器請參考:/category/selectors/

構(gòu)造jQuery對象

//from選擇器

$('#publish-dialoga.close');

//fromdom節(jié)點(diǎn)

vardom=$('#doc')[0];

$(dom);

//fromjquery對象

varchooser=$('div.offer-chooser');

varpanel=chooser.find('ul.chooser-panel');

或者

varpanel=$('ul.chooser-panel',chooser);//內(nèi)部調(diào)用find來完成

jquery對象結(jié)構(gòu)

如果針對本文檔,在firefoxscriptwatch中輸入jQuery('ul'),將創(chuàng)建一個jQuery對象,

用于操作文檔中所有ul節(jié)點(diǎn),展開它會看到如下對象結(jié)構(gòu)

{

0:ul,//HTMLUListElement,即原生dom節(jié)點(diǎn)對象

1:ul,

2:ul,

...

7:ul,length:8,selector:'ul',

context:document,

prevObject:document

...

}

jQuery對象是一個普通對象,有數(shù)組相似的接口,所以可以像數(shù)組一樣參于迭代

構(gòu)造一個jQuery對象成本不大,因?yàn)橹话恍┮米侄?沒有大數(shù)據(jù)字段

了解這個是為了讓我們更好地使用jQuery,而不是把$(美元符號)當(dāng)作一種奇怪的語法來用.

見下面這段jQuery初學(xué)者常見的代碼

$('a.close',div).click(function(){

$(this).addClass('abc');

if(...){

$(this).attr(...)

}else{

$(this).data(...);

}$(this)...

});

為了增加可讀性,提高效率和減少不必要的內(nèi)存消耗,請記住$(elm)等于newjQuery(elm);

只構(gòu)造必要的jQuery對象,上述代碼可以這么寫

elms.click(function(){

varelm=$(this);//保存引用

...

});

基本操作

varlis=$('ul.offer-listli');

if(!lislength){//判斷節(jié)點(diǎn)是否存在

return;

}lis.eq(0).addClass('first');//只對第一個節(jié)點(diǎn)處理,相當(dāng)于$(lis[0]).addClass('first');varfirstLi=lis[0];//取得第1個節(jié)點(diǎn)(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:'設(shè)置'

width:'700',

height:'350',

confirm:function(){

...

}

});

});

上述事件掛接,也可以使用bind

button.bind('click',function(e){

...

});

click方法只是bind方法的一個包裝,相似的還有其他事件:change,resize,dblclick,keypress等

幾乎所有常用的瀏覽器事件都有直接對應(yīng)的方法用于掛接或觸發(fā)事件

關(guān)于其他事件請參考:/category/events/

關(guān)于事件函數(shù)有幾點(diǎn)說明:

關(guān)于this

this指向觸發(fā)事件的元素(htmldom節(jié)點(diǎn))

$('a.delete',list).click(function(e){

e.prevent();varlink=$(this),//here,isahtmlelement

li=link.closest('li'),postId=li.data('postId');Post.delete(postId);

});

關(guān)于參數(shù)event

我們可以從中獲取一些關(guān)于事件的參數(shù),如鼠標(biāo)位置,鍵盤輸入等等,

或者取消瀏覽器默認(rèn)事件,阻止冒泡

$('a.close',dialog).click(function(e){

e.preventDefault();//阻止鏈接正常行為,

//因?yàn)檫@個鏈接是作為功能按扭來使用的,而不需要跳轉(zhuǎn)或重新定位瞄點(diǎn)

...

});

$('div.canvas').mousemove(function(e){

varx=e.pageX,//鼠標(biāo)位置

y=e.pageY;});$('input.username').keydown(function(e){

varself=this;if(e.keyCode===13){//回車

self.submitForm();

}

});

關(guān)于eventobject請參考:/category/events/event-object/

觸發(fā)事件

有時候需要人為地觸發(fā)一個瀏覽器事件,如提交表單

或者打開浮層登錄框框后需要默認(rèn)選擇第二個tab,就相當(dāng)于"按"一下那個tab

form.submit();

tabs.eq(2).click();

或者

form.trigger('submit');

tabs.eq(2).trigger('click');

同bind,無參數(shù)的click或submit只是trigger的一個包裝

trigger它會執(zhí)行瀏覽器默認(rèn)行為,比如當(dāng)你click一個checkbox的時候,界面中的checkbox也會勾選或取消勾選

同時trigger還會冒泡(關(guān)于事件冒泡,下面會有)

如果只想執(zhí)行事件,而不觸發(fā)默認(rèn)行為,請使用triggerHandler

同時trigger和triggerHandler還支持額外的參數(shù),具體可參考文檔

/trigger/

/triggerHandler/

事件冒泡

body

div#doc

div#header

div.search-bar

input.search-btn[type=button]

當(dāng)我們點(diǎn)擊input.search-btn時,input.search-btn,div.search-bar,div.#header,div#doc,body依次會觸發(fā)click事件.

這個過程叫事件冒泡

關(guān)于事件冒泡更細(xì)致的內(nèi)容可參考:/category/events/

所以如果我們所事件函數(shù)掛接在外圍節(jié)點(diǎn),將能接收到里面子節(jié)點(diǎn)的事件.

容器內(nèi)部節(jié)點(diǎn)動態(tài)創(chuàng)建的事件綁定

div.click(function(e){

if($(e.target).is('a.delete')){

//..

}

});以上代碼可以這樣寫:div.delegate('a.delete','click',function(){});

如果有很多個節(jié)點(diǎn)需要綁定事件,此時可以使用冒泡綁定在外圍容器上,很大地提高效率//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:'點(diǎn)擊發(fā)布可應(yīng)用您的修改到旺鋪'

});

});

}

namespace事件

$('a.mylink').bind('click',function(){});$('a.mylink').bind('click.mylink',function(){});//移除事件

$('a.mylink').unbind('click.mylink');

//觸發(fā)指定namespace事件

$('a.mylink').triggerHandler('click.mylink');

關(guān)于namespace的參考鏈接,官網(wǎng)上我一時找不到了,不好意思,以前記得有的,現(xiàn)在只有一點(diǎn)點(diǎn):

/bind/

/unbind/

或者直接參看源碼可能會更清晰:jquery1.6.2,第2619行,第2726行,第2810行

操作

節(jié)點(diǎn)操作的api可直接參考/category/manipulation/

有幾點(diǎn)需要說明,dom節(jié)點(diǎn)操作是所有操作里最慢的,往往頁面的效率瓶頸就在dom操作,所以要特別注意

改變屬性的操作如:addClass,removeClass,css等需要瀏覽器重繪節(jié)點(diǎn)

而html,append,prepand,等節(jié)點(diǎn)操作需要瀏覽器重排節(jié)點(diǎn)并且重繪

具體請參考:《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. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論