今天小編要跟大家分享的文章是關(guān)于Web前端新手應(yīng)該知道的JavaScript開發(fā)技巧有哪些?熟悉Web前端的小伙伴都知道,Javascript
10年積累的網(wǎng)站制作、成都網(wǎng)站制作經(jīng)驗(yàn),可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站設(shè)計(jì)后付款的網(wǎng)站建設(shè)流程,更有鄂溫克免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
的很多擴(kuò)展的特性是的它變得更加的犀利,同時(shí)也給予程序員機(jī)會(huì)創(chuàng)建更漂亮并且更讓用戶喜歡的網(wǎng)站。
盡管很多的開發(fā)人員都樂于頌揚(yáng)javascript,但是仍舊有人看到它的陰暗面。
使用很多javascript代碼的Web頁面會(huì)加載很慢,過多的使用javascript使得網(wǎng)頁丑陋和拖沓。很快如何有效地使用
javascript成為一個(gè)非常火熱的話題。
今天小編就為Web前端新手準(zhǔn)備了這篇JavaScript開發(fā)技巧,希望能夠?qū)δ阌兴鶐椭旅嫖覀円黄饋砜匆豢窗?
1、盡可能的保持代碼簡潔
可能大家都聽到過了N遍這個(gè)代碼簡潔問題了。作為一個(gè)開發(fā)人員你可能在你的代碼開發(fā)過程中使用了很多次,但千萬不要在js開發(fā)中忘記這點(diǎn)。
§盡量在開發(fā)模式中添加注釋和空格,這樣保持代碼的可讀性
§在發(fā)布到產(chǎn)品環(huán)境前請將空格和注釋都刪除,并且盡量縮寫變量和方法名
§使用第三方工具幫助你實(shí)現(xiàn)壓縮javascript。
2、思考后再修改prototypes
添加新的屬性到對象prototype中是導(dǎo)致腳本出錯(cuò)的常見原因。
yourObject.prototype.anotherFunction='Hello';
yourObject.prototype.anotherMethod=function(){...}
在上面代碼中,所有的變量都會(huì)被影響,因?yàn)樗麄兌祭^承于yourObject。這樣的使用會(huì)導(dǎo)致意想不到的行為。所以建議在使用完后刪除類似的修改。
yourObject.prototype.anotherFunction='Hello';
yourObject.prototype.anotherMethod=function(){};
test.anotherMethod();
deleteyourObject.prototype.anotherFunction='Hello';
deleteyourObject.prototype.anotherMethod=function(){};
3、DebugJavascript代碼
即使最好的開發(fā)人員都會(huì)犯錯(cuò)。為了最大化的減少類似錯(cuò)誤,請?jiān)谀愕膁ebugger中運(yùn)行你的代碼,確認(rèn)你沒有遇到任何細(xì)微的錯(cuò)誤。
4、避免Eval
你的JS在沒有eval方法的時(shí)候也可以很好的工作。eval允許訪問javascript編譯器。如果一個(gè)字符串作為參數(shù)傳遞到
eval,那么它的結(jié)果可以被執(zhí)行。
這會(huì)很大的降低代碼的性能。盡量避免在產(chǎn)品環(huán)境中使用eval。
5、最小化DOM訪問
DOM是最復(fù)雜的API,會(huì)使得代碼執(zhí)行過程變慢。有時(shí)候Web頁面可能沒有加載或者加載不完整。最好避免DOM。
6、在使用javascript類庫之前先學(xué)習(xí)javascript
互聯(lián)網(wǎng)充斥著很多的javascript類庫,很多程序員都往往使用js類庫而不理解負(fù)面影響。強(qiáng)烈建議你在使用第三方類庫之前學(xué)習(xí)基本的JS
代碼,否則,你就準(zhǔn)備著倒霉吧。
7、不要用“SetTimeOut”和“Setinterval”方法來作為“Eval”的備選
setTimeOut("document.getID('value')",3000);
在以上代碼中document.getID(‘value’)在setTimeOut方法中被作為字符串來處理。這類似于eval
方法,在每個(gè)代碼執(zhí)行中來執(zhí)行一個(gè)字符串,因此會(huì)降低性能,因此,建議在這些方法中傳遞一個(gè)方法。
setTimeOut(yourFunction,3000);
8、[]比newArray();更好
一個(gè)常犯的錯(cuò)誤在于使用當(dāng)需要數(shù)組的時(shí)候使用一個(gè)對象或者該使用對象的時(shí)候使用一個(gè)數(shù)組。但是使用原則很簡單:
“當(dāng)屬性名稱是小的連續(xù)整數(shù),你應(yīng)該使用數(shù)組。否則,使用一個(gè)對象”_DouglasCrockford,JavaScript:Good
Parts的作者.
建議:
vara=['1A','2B'];
避免:
vara=newArray();
a[0]="1A";
a[1]="2B";
9、盡量不要多次使用var
在初始每一個(gè)變量的時(shí)候,程序員都習(xí)慣使用var關(guān)鍵字。相反,建議你使用逗號(hào)來避免多余的關(guān)鍵字,并且減少代碼體積。如下:
varvariableOne='string1',
variableTwo='string2',
variableThree='string3';
10、不要忽略分號(hào)“;”
這往往是大家花費(fèi)數(shù)個(gè)小時(shí)進(jìn)行debug的原因之一。
我很確信你肯定也在其它的文章中閱讀過以上相關(guān)的內(nèi)容,但是大家可能往往都忽略了很多基本的規(guī)則。你是不是也曾經(jīng)忽略過分號(hào)。是不是也遇到過eval
關(guān)鍵字問題導(dǎo)致性能問題?
以上就是小編今天為大家分享的關(guān)于Web前端新手應(yīng)該知道的JavaScript
開發(fā)技巧有哪些?的文章,希望本篇文章能夠?qū)倓偨佑|Web前端行業(yè)的新手們有所幫助。想要了解更多Web前端知識(shí)記得關(guān)注北大青鳥Web前端培訓(xùn)官網(wǎng)!
*聲明:內(nèi)容與圖片均來源于網(wǎng)絡(luò)(部分內(nèi)容有修改),版權(quán)歸原作者所有,如來源信息有誤或侵犯權(quán)益,請聯(lián)系我們刪除或授權(quán)事宜。
javascript權(quán)威指南, 強(qiáng)烈推薦這本書,但是我工作的時(shí)候每天下班之后拿一個(gè)小時(shí)看這本書,然后做些小例子,熟悉語法知識(shí),后面看到類,方法那張感覺看的不是很懂,就沒繼續(xù)看了,現(xiàn)在的項(xiàng)目里大量運(yùn)用類,方法,一開始看的很頭疼,習(xí)慣了就感覺挺好的, 我現(xiàn)在在做兼容這一塊,, 等做完了繼續(xù)看這本書的高級(jí)部分。 書不是看的越多越好,需要你自己多動(dòng)手,遇到不會(huì)的了查下資料,慢慢積累,然后再去看書,這樣會(huì)收獲很多,你光看書會(huì)覺得這也會(huì)那也會(huì),但是你沒用運(yùn)用,過幾天十點(diǎn)能記住兩點(diǎn)就不錯(cuò)了。
今天小編要跟大家分享的文章是關(guān)于Web前端工程師應(yīng)該知道的JavaScript使用小技巧。任何一門技術(shù)在實(shí)際中都會(huì)有一些屬于自己的小技巧。同樣的,在使用JavaScript時(shí)也有一些自己的小技巧,只不過很多時(shí)候有可能容易被大家忽略。而在互聯(lián)網(wǎng)上,時(shí)不時(shí)的有很多同行朋友會(huì)總結(jié)(或收集)一些這方面的小技巧。
今天在這篇文章中,小編會(huì)整理一些大家熟悉或不熟悉的有關(guān)于JavaScript的小技巧,希望能夠?qū)Υ蠹业膶W(xué)習(xí)和工作有所幫助。
一、數(shù)組
先來看使用數(shù)組中常用的一些小技巧。
01、數(shù)組去重
ES6提供了幾種簡潔的數(shù)組去重的方法,但該方法并不適合處理非基本類型的數(shù)組。對于基本類型的數(shù)組去重,可以使用...new
Set()來過濾掉數(shù)組中重復(fù)的值,創(chuàng)建一個(gè)只有唯一值的新數(shù)組。
constarray=[1,1,2,3,5,5,1]
constuniqueArray=[...newSet(array)];
console.log(uniqueArray);
Result:(4)[1,2,3,5]
這是ES6中的新特性,在ES6之前,要實(shí)現(xiàn)同樣的效果,我們需要使用更多的代碼。該技巧適用于包含基本類型的數(shù)組:undefined、null、boolean、string和number。如果數(shù)組中包含了一個(gè)object,function或其他數(shù)組,那就需要使用另一種方法。
除了上面的方法之外,還可以使用Array.from(newSet())來實(shí)現(xiàn):
constarray=[1,1,2,3,5,5,1]
Array.from(newSet(array))
Result:(4)[1,2,3,5]
另外,還可以使用Array的.filter及indexOf()來實(shí)現(xiàn):
constarray=[1,1,2,3,5,5,1]
array.filter((arr,index)=array.indexOf(arr)===index)
Result:(4)[1,2,3,5]
注意,indexOf()方法將返回?cái)?shù)組中第一個(gè)出現(xiàn)的數(shù)組項(xiàng)。這就是為什么我們可以在每次迭代中將indexOf()方法返回的索引與當(dāng)索索引進(jìn)行比較,以確定當(dāng)前項(xiàng)是否重復(fù)。
02、確保數(shù)組的長度
在處理網(wǎng)格結(jié)構(gòu)時(shí),如果原始數(shù)據(jù)每行的長度不相等,就需要重新創(chuàng)建該數(shù)據(jù)。為了確保每行的數(shù)據(jù)長度相等,可以使用Array.fill來處理:
letarray=Array(5).fill('');
console.log(array);
Result:(5)["","","","",""]
03、數(shù)組映射
不使用Array.map來映射數(shù)組值的方法。
constarray=[
{
ame:'大漠',
email:'w3cplus@#'
},
{
ame:'Airen',
email:'airen@#'
}
]
constname=Array.from(array,({name})=name)
Result:(2)["大漠","Airen"]
04、數(shù)組截?cái)?/p>
如果你想從數(shù)組末尾刪除值(刪除數(shù)組中的最后一項(xiàng)),有比使用splice()更快的替代方法。
例如,你知道原始數(shù)組的大小,可以重新定義數(shù)組的length屬性的值,就可以實(shí)現(xiàn)從數(shù)組末尾刪除值:
letarray=[0,1,2,3,4,5,6,7,8,9]
console.log(array.length)
Result:10
array.length=4
console.log(array)
Result:(4)[0,1,2,3]
這是一個(gè)特別簡潔的解決方案。但是,slice()方法運(yùn)行更快,性能更好:
letarray=[0,1,2,3,4,5,6,7,8,9];
array=array.slice(0,4);
console.log(array);
Result:[0,1,2,3]
05、過濾掉數(shù)組中的falsy值
如果你想過濾數(shù)組中的falsy值,比如0、undefined、null、false,那么可以通過map和filter方法實(shí)現(xiàn):
constarray=[0,1,'0','1','大漠','#',undefined,true,false,null,'undefined','null',NaN,'NaN','1'+0]
array.map(item={
returnitem
}).filter(Boolean)
Result:(10)[1,"0","1","大漠","#",true,"undefined","null","NaN","10"]
06、獲取數(shù)組的最后一項(xiàng)
數(shù)組的slice()取值為正值時(shí),從數(shù)組的開始處截取數(shù)組的項(xiàng),如果取值為負(fù)整數(shù)時(shí),可以從數(shù)組末屬開始獲取數(shù)組項(xiàng)。
letarray=[1,2,3,4,5,6,7]
constfirstArrayVal=array.slice(0,1)
Result:[1]
constlastArrayVal=array.slice(-1)
Result:[7]
console.log(array.slice(1))
Result:(6)[2,3,4,5,6,7]
console.log(array.slice(array.length))
Result:[]
正如上面示例所示,使用array.slice(-1)獲取數(shù)組的最后一項(xiàng),除此之外還可以使用下面的方式來獲取數(shù)組的最后一項(xiàng):
console.log(array.slice(array.length-1))
Result:[7]
07、過濾并排序字符串列表
你可能有一個(gè)很多名字組成的列表,需要過濾掉重復(fù)的名字并按字母表將其排序。
在我們的例子里準(zhǔn)備用不同版本語言的JavaScript
保留字的列表,但是你能發(fā)現(xiàn),有很多重復(fù)的關(guān)鍵字而且它們并沒有按字母表順序排列。所以這是一個(gè)完美的字符串列表(數(shù)組)來測試我們的JavaScript小知識(shí)。
varkeywords=['do','if','in','for','new','try','var','case','else','enum','null','this','true','void','with','break','catch','class','const','false','super','throw','while','delete','export','import','return','switch','typeof','default','extends','finally','continue','debugger','function','do','if','in','for','int','new','try','var','byte','case','char','else','enum','goto','long','null','this','true','void','with','break','catch','class','const','false','final','float','short','super','throw','while','delete','double','export','import','native','public','return','static','switch','throws','typeof','boolean','default','extends','finally','package','private','abstract','continue','debugger','function','volatile','interface','protected','transient','implements','instanceof','synchronized','do','if','in','for','let','new','try','var','case','else','enum','eval','null','this','true','void','with','break','catch','class','const','false','super','throw','while','yield','delete','export','import','public','return','static','switch','typeof','default','extends','finally','package','private','continue','debugger','function','arguments','interface','protected','implements','instanceof','do','if','in','for','let','new','try','var','case','else','enum','eval','null','this','true','void','with','await','break','catch','class','const','false','super','throw','while','yield','delete','export','import','public','return','static','switch','typeof','default','extends','finally','package','private','continue','debugger','function','arguments','interface','protected','implements','instanceof'];
因?yàn)槲覀儾幌敫淖兾覀兊脑剂斜?,所以我們?zhǔn)備用高階函數(shù)叫做filter,它將基于我們傳遞的回調(diào)方法返回一個(gè)新的過濾后的數(shù)組?;卣{(diào)方法將比較當(dāng)前關(guān)鍵字在原始列表里的索引和新列表中的索引,僅當(dāng)索引匹配時(shí)將當(dāng)前關(guān)鍵字push到新數(shù)組。
最后我們準(zhǔn)備使用sort方法排序過濾后的列表,sort只接受一個(gè)比較方法作為參數(shù),并返回按字母表排序后的列表。
在ES6下使用箭頭函數(shù)看起來更簡單:
constfilteredAndSortedKeywords=keywords
.filter((keyword,index)=keywords.lastIndexOf(keyword)===index)
.sort((a,b)=a
這是最后過濾和排序后的JavaScript保留字列表:
console.log(filteredAndSortedKeywords);
Result:['abstract','arguments','await','boolean','break','byte','case','catch','char','class','const','continue','debugger','default','delete','do','double','else','enum','eval','export','extends','false','final','finally','float','for','function','goto','if','implements','import','in','instanceof','int','interface','let','long','native','new','null','package','private','protected','public','return','short','static','super','switch','synchronized','this','throw','throws','transient','true','try','typeof','var','void','volatile','while','with','yield']
08、清空數(shù)組
如果你定義了一個(gè)數(shù)組,然后你想清空它。通常,你會(huì)這樣做:
letarray=[1,2,3,4];
functionemptyArray(){
array=[];
}
emptyArray();
但是,這有一個(gè)效率更高的方法來清空數(shù)組。你可以這樣寫:
letarray=[1,2,3,4];
functionemptyArray(){
array.length=0;
}
emptyArray();
09、拍平多維數(shù)組
使用...運(yùn)算符,將多維數(shù)組拍平:
10、從數(shù)組中獲取最大值和最小值
可以使用Math.max和Math.min取出數(shù)組中的最大小值和最小值:
constnumbers=[15,80,-9,90,-99]
constmaxInNumbers=Math.max.apply(Math,numbers)
constminInNumbers=Math.min.apply(Math,numbers)
console.log(maxInNumbers)
Result:90
console.log(minInNumbers)
Result:-99
另外還可以使用ES6的...運(yùn)算符來完成:
constnumbers=[1,2,3,4];
Math.max(...numbers)
Result:4
Math.min(...numbers)
Result:1
二、對象
在操作對象時(shí)也有一些小技巧。
01、使用...運(yùn)算符合并對象或數(shù)組中的對象
同樣使用ES的...運(yùn)算符可以替代人工操作,合并對象或者合并數(shù)組中的對象。
//合并對象
constobj1={
ame:'大漠',
url:'#'
}
constobj2={
ame:'airen',
age:30
}
constmergingObj={...obj1,...obj2}
Result:{name:"airen",url:"#",age:30}
//合并數(shù)組中的對象
constarray=[
{
ame:'大漠',
email:'w3cplus@#'
},
{
ame:'Airen',
email:'airen@#'
}
]
constresult=array.reduce((accumulator,item)={
return{
...accumulator,
[item.name]:item.email
}
},{})
Result:{大漠:"w3cplus@#",Airen:"airen@#"}
02、有條件的添加對象屬性
不再需要根據(jù)一個(gè)條件創(chuàng)建兩個(gè)不同的對象,以使它具有特定的屬性。為此,使用...操作符是最簡單的。
constgetUser=(emailIncluded)={
return{
ame:'大漠',
blog:'w3cplus',
...emailIncluded{email:'w3cplus@#'}
}
}
constuser=getUser(true)
console.log(user)
Result:{name:"大漠",blog:"w3cplus",email:"w3cplus@#"}
constuserWithoutEmail=getUser(false)
console.log(userWithoutEmail)
Result:{name:"大漠",blog:"w3cplus"}
03、解構(gòu)原始數(shù)據(jù)
你可以在使用數(shù)據(jù)的時(shí)候,把所有數(shù)據(jù)都放在一個(gè)對象中。同時(shí)想在這個(gè)數(shù)據(jù)對象中獲取自己想要的數(shù)據(jù)。
在這里可以使用ES6的Destructuring特性來實(shí)現(xiàn)。比如你想把下面這個(gè)obj中的數(shù)據(jù)分成兩個(gè)部分:
constobj={
ame:'大漠',
blog:'w3cplus',
email:'w3cplus@#',
joined:'2019-06-19',
followers:45
}
letuser={},userDetails={}
({name:user.name,email:user.email,...userDetails}=obj)
{name:"大漠",blog:"w3cplus",email:"w3cplus@#",joined:"2019-06-19",followers:45}
console.log(user)
Result:{name:"大漠",email:"w3cplus@#"}
console.log(userDetails)
Result:{blog:"w3cplus",joined:"2019-06-19",followers:45}
04、動(dòng)態(tài)更改對象的key
在過去,我們首先必須聲明一個(gè)對象,然后在需要?jiǎng)討B(tài)屬性名的情況下分配一個(gè)屬性。在以前,這是不可能以聲明的方式實(shí)現(xiàn)的。不過在ES6中,我們可以實(shí)現(xiàn):
constdynamicKey='email'
letobj={
ame:'大漠',
blog:'w3cplus',
[dynamicKey]:'w3cplus@#'
}
console.log(obj)
Result:{name:"大漠",blog:"w3cplus",email:"w3cplus@#"}
05、判斷對象的數(shù)據(jù)類型
使用Object.prototype.toString配合閉包來實(shí)現(xiàn)對象數(shù)據(jù)類型的判斷:
constisType=type=target=`[object${type}]`===Object.prototype.toString.call(target)
constisArray=isType('Array')([1,2,3])
console.log(isArray)
Result:true
上面的代碼相當(dāng)于:
functionisType(type){
returnfunction(target){
return`[object${type}]`===Object.prototype.toString.call(target)
}
}
isType('Array')([1,2,3])
Result:true
或者:
constisType=type=target=`[object${type}]`===Object.prototype.toString.call(target)
constisString=isType('String')
constres=isString(('1'))
console.log(res)
Result:true
06、檢查某對象是否有某屬性
當(dāng)你需要檢查某屬性是否存在于一個(gè)對象,你可能會(huì)這樣做:
varobj={
ame:'大漠'
}
if(obj.name){
console.l
這篇帖子詳細(xì)的介紹了javascript的執(zhí)行順序 希望對你有用 望采納 在這貼出帖子內(nèi)容
1.1
按HTML文檔流順序執(zhí)行JavaScript代碼
首先,讀者應(yīng)該清楚,HTML文檔在瀏覽器中的解析過程是這樣的:瀏覽器是按著文檔流從上到下逐步解析頁面結(jié)構(gòu)和信息的。JavaScript代碼作為嵌入的腳本應(yīng)該也算做HTML文檔的組成部分,所以JavaScript代碼在裝載時(shí)的執(zhí)行順序也是根據(jù)腳本標(biāo)簽script的出現(xiàn)順序來確定的。例如,瀏覽下面文檔頁面,你會(huì)看到代碼是從上到下逐步被解析的。
復(fù)制代碼
代碼如下:
script
alert("頂部腳本");
/script
htmlhead
script
alert("頭部腳本");
/script
title/title
/head
body
script
alert("頁面腳本");
/script
/body/html
script
alert("底部腳本");
/script
如果通過腳本標(biāo)簽script的src屬性導(dǎo)入外部JavaScript文件腳本,那么它也將按照其語句出現(xiàn)的順序來執(zhí)行,而且執(zhí)行過程是文檔裝載的一部分。不會(huì)因?yàn)槭峭獠縅avaScript文件而延期執(zhí)行。例如,把上面文檔中的頭部和主體區(qū)域的腳本移到外部JavaScript文件中,然后通過src屬性導(dǎo)入。繼續(xù)預(yù)覽頁面文檔,你會(huì)看到相同的執(zhí)行順序。
復(fù)制代碼
代碼如下:
script
alert("頂部腳本");
/script
html
head
script src=""/script
title/title
/head
body
script src=""/script
/body
/html
script
alert("底部腳本");
/script
1.2 預(yù)編譯與執(zhí)行順序的關(guān)系
在Javascript中,function才是Javascript的第一型。當(dāng)我們寫下一段函數(shù)時(shí),其實(shí)不過是建立了一個(gè)function類型的實(shí)體。
就像我們可以寫成這樣的形式一樣:
復(fù)制代碼
代碼如下:
functionHello()
{
alert("Hello");
}
Hello();
varHello = function()
{
alert("Hello");
}
Hello();
其實(shí)都是一樣的。 但是當(dāng)我們對其中的函數(shù)進(jìn)行修改時(shí),會(huì)發(fā)現(xiàn)很奇怪的問題。
復(fù)制代碼
代碼如下:
scripttype="text/javascript"
functionHello() {
alert("Hello");
}
Hello();
functionHello() {
alert("Hello World");
}
Hello();
/script
我們會(huì)看到這樣的結(jié)果:連續(xù)輸出了兩次Hello
World。
而非我們想象中的Hello和Hello World。
這是因?yàn)镴avascript并非完全的按順序解釋執(zhí)行,而是在解釋之前會(huì)對Javascript進(jìn)行一次“預(yù)編譯”,在預(yù)編譯的過程中,會(huì)把定義式的函數(shù)優(yōu)先執(zhí)行,也會(huì)把所有var變量創(chuàng)建,默認(rèn)值為undefined,以提高程序的執(zhí)行效率。
也就是說上面的一段代碼其實(shí)被JS引擎預(yù)編譯為這樣的形式:
復(fù)制代碼
代碼如下:
scripttype="text/javascript"
varHello = function() {
alert("Hello");
}
Hello = function() {
alert("Hello World");
}
Hello();
Hello();
/script
我們可以通過上面的代碼很清晰地看到,其實(shí)函數(shù)也是數(shù)據(jù),也是變量,我們也可以對“函數(shù)“進(jìn)行賦值(重賦值)。
當(dāng)然,我們?yōu)榱朔乐惯@樣的情況,也可以這樣:
復(fù)制代碼
代碼如下:
scripttype="text/javascript"
functionHello() {
alert("Hello");
}
Hello();
/script
scripttype="text/javascript"
functionHello() {
alert("Hello World");
}
Hello();
/script
這樣,程序被分成了兩段,JS引擎也就不會(huì)把他們放到一起了。
當(dāng)JavaScript引擎解析腳本時(shí),它會(huì)在預(yù)編譯期對所有聲明的變量和函數(shù)進(jìn)行處理。
做如下處理:
1.
在執(zhí)行前會(huì)進(jìn)行類似“預(yù)編譯”的操作:首先會(huì)創(chuàng)建一個(gè)當(dāng)前執(zhí)行環(huán)境下的活動(dòng)對象,并將那些用var申明的變量設(shè)置為活動(dòng)對象的屬性,但是此時(shí)這些變量的賦值都是undefined,并將那些以function定義的函數(shù)也添加為活動(dòng)對象的屬性,而且它們的值正是函數(shù)的定義。
2.
在解釋執(zhí)行階段,遇到變量需要解析時(shí),會(huì)首先從當(dāng)前執(zhí)行環(huán)境的活動(dòng)對象中查找,如果沒有找到而且該執(zhí)行環(huán)境的擁有者有prototype屬性時(shí)則會(huì)從prototype鏈中查找,否則將會(huì)按照作用域鏈查找。遇到var
a = ...這樣的語句時(shí)會(huì)給相應(yīng)的變量進(jìn)行賦值(注意:變量的賦值是在解釋執(zhí)行階段完成的,如果在這之前使用變量,它的值會(huì)是undefined)
所以,就會(huì)出現(xiàn)當(dāng)JavaScript解釋器執(zhí)行下面腳本時(shí)不會(huì)報(bào)錯(cuò):
復(fù)制代碼
代碼如下:
alert(a); //
返回值undefined
var a =1;
alert(a); //
返回值1
由于變量聲明是在預(yù)編譯期被處理的,所以在執(zhí)行期間對于所有代碼來說,都是可見的。但是,你也會(huì)看到,執(zhí)行上面代碼,提示的值是undefined,而不是1。這是因?yàn)?,變量初始化過程發(fā)生在執(zhí)行期,而不是預(yù)編譯期。在執(zhí)行期,JavaScript解釋器是按著代碼先后順序進(jìn)行解析的,如果在前面代碼行中沒有為變量賦值,則JavaScript解釋器會(huì)使用默認(rèn)值undefined。由于在第二行中為變量a賦值了,所以在第三行代碼中會(huì)提示變量a的值為1,而不是undefined。
同理,下面示例在函數(shù)聲明前調(diào)用函數(shù)也是合法的,并能夠被正確解析,所以返回值為1。
復(fù)制代碼
代碼如下:
f(); //
調(diào)用函數(shù),返回值1
function f(){
alert(1);
}
但是,如果按下面方式定義函數(shù),則JavaScript解釋器會(huì)提示語法錯(cuò)誤。
復(fù)制代碼
代碼如下:
f(); //
調(diào)用函數(shù),返回語法錯(cuò)誤
var f = function(){
alert(1);
}
這是因?yàn)椋厦媸纠卸x的函數(shù)僅作為值賦值給變量f,所以在預(yù)編譯期,JavaScript解釋器只能夠?yàn)槁暶髯兞縡進(jìn)行處理,而對于變量f的值,只能等到執(zhí)行期時(shí)按順序進(jìn)行賦值,自然就會(huì)出現(xiàn)語法錯(cuò)誤,提示找不到對象f。
再見一些例子:
復(fù)制代碼
代碼如下:
script type="text/javascript"
/*在預(yù)編譯過程中func是window環(huán)境下的活動(dòng)對象中的一個(gè)屬性,值是一個(gè)函數(shù),覆蓋了undefined值*/
alert(func); //function func(){alert("hello!")}
var func = "this is a variable"
function func(){
alert("hello!")
}
/*在執(zhí)行過程中遇到了var重新賦值為"this is a variable"*/
alert(func); //this is a variable
/script
復(fù)制代碼
代碼如下:
script type="text/javascript"
var name = "feng"; function func()
{
/*首先,在func環(huán)境內(nèi)先把name賦值為undefined,然后在執(zhí)行過程中先尋找func環(huán)境下的活動(dòng)對象的name屬性,此時(shí)之前已經(jīng)預(yù)編譯值為undefined,所以輸出是undefined,而不是feng*/
alert(name); //undefined var name = "JSF";
alert(name); //JSF
}
func();
alert(name);
//feng
/script
雖然變量和函數(shù)聲明可以在文檔任意位置,但是良好的習(xí)慣應(yīng)該是在所有JavaScript代碼之前聲明全局變量和函數(shù),并對變量進(jìn)行初始化賦值。在函數(shù)內(nèi)部也是先聲明變量,然后再引用。
1.3 按塊執(zhí)行JavaScript代碼
所謂代碼塊就是使用script標(biāo)簽分隔的代碼段。例如,下面兩個(gè)script標(biāo)簽分別代表兩個(gè)JavaScript代碼塊。
復(fù)制代碼
代碼如下:
script
// JavaScript代碼塊1
var a =1;
/script
script
// JavaScript代碼塊2
function f(){
alert(1);
}
/script
JavaScript解釋器在執(zhí)行腳本時(shí),是按塊來執(zhí)行的。通俗地說,就是瀏覽器在解析HTML文檔流時(shí),如果遇到一個(gè)script標(biāo)簽,則JavaScript解釋器會(huì)等到這個(gè)代碼塊都加載完后,先對代碼塊進(jìn)行預(yù)編譯,然后再執(zhí)行。執(zhí)行完畢后,瀏覽器會(huì)繼續(xù)解析下面的HTML文檔流,同時(shí)JavaScript解釋器也準(zhǔn)備好處理下一個(gè)代碼塊。
由于JavaScript是按塊執(zhí)行的,所以如果在一個(gè)JavaScript塊中調(diào)用后面塊中聲明的變量或函數(shù)就會(huì)提示語法錯(cuò)誤。例如,當(dāng)JavaScript解釋器執(zhí)行下面代碼時(shí)就會(huì)提示語法錯(cuò)誤,顯示變量a未定義,對象f找不到。
復(fù)制代碼
代碼如下:
script
// JavaScript代碼塊1
alert(a);
f();
/script
script
// JavaScript代碼塊2
var a =1;
function f(){
alert(1);
}
/script
雖然說,JavaScript是按塊執(zhí)行的,但是不同塊都屬于同一個(gè)全局作用域,也就是說,塊之間的變量和函數(shù)是可以共享的。
1.4 借助事件機(jī)制改變JavaScript執(zhí)行順序
由于JavaScript是按塊處理代碼,同時(shí)又遵循HTML文檔流的解析順序,所以在上面示例中會(huì)看到這樣的語法錯(cuò)誤。但是當(dāng)文檔流加載完畢,如果再次訪問就不會(huì)出現(xiàn)這樣的錯(cuò)誤。例如,把訪問第2塊代碼中的變量和函數(shù)的代碼放在頁面初始化事件函數(shù)中,就不會(huì)出現(xiàn)語法錯(cuò)誤了。
復(fù)制代碼
代碼如下:
script
// JavaScript代碼塊1
window.onload = function(){ // 頁面初始化事件處理函數(shù)
alert(a);
f();
}
/script
script
// JavaScript代碼塊2
var a =1;
function f(){
alert(1);
}
/script
為了安全起見,我們一般在頁面初始化完畢之后才允許JavaScript代碼執(zhí)行,這樣可以避免網(wǎng)速對JavaScript執(zhí)行的影響,同時(shí)也避開了HTML文檔流對于JavaScript執(zhí)行的限制。
注意
如果在一個(gè)頁面中存在多個(gè)windows.onload事件處理函數(shù),則只有最后一個(gè)才是有效的,為了解決這個(gè)問題,可以把所有腳本或調(diào)用函數(shù)都放在同一個(gè)onload事件處理函數(shù)中,例如:
復(fù)制代碼
代碼如下:
window.onload = function(){
f1();
f2();
f3();
}
而且通過這種方式可以改變函數(shù)的執(zhí)行順序,方法是:簡單地調(diào)整onload事件處理函數(shù)中調(diào)用函數(shù)的排列順序。
除了頁面初始化事件外,我們還可以通過各種交互事件來改變JavaScript代碼的執(zhí)行順序,如鼠標(biāo)事件、鍵盤事件及時(shí)鐘觸發(fā)器等方法,詳細(xì)講解請參閱第14章的內(nèi)容。
1.5 JavaScript輸出腳本的執(zhí)行順序
在JavaScript開發(fā)中,經(jīng)常會(huì)使用document對象的write()方法輸出JavaScript腳本。那么這些動(dòng)態(tài)輸出的腳本是如何執(zhí)行的呢?例如:
復(fù)制代碼
代碼如下:
document.write('script
type="text/javascript"');
document.write('f();');
document.write('function f(){');
document.write('alert(1);');
document.write('}');
document.write('/script');
運(yùn)行上面代碼,我們會(huì)發(fā)現(xiàn):document.write()方法先把輸出的腳本字符串寫入到腳本所在的文檔位置,瀏覽器在解析完document.write()所在文檔內(nèi)容后,繼續(xù)解析document.write()輸出的內(nèi)容,然后才按順序解析后面的HTML文檔。也就是說,JavaScript腳本輸出的代碼字符串會(huì)在輸出后馬上被執(zhí)行。
請注意,使用document.write()方法輸出的JavaScript腳本字符串必須放在同時(shí)被輸出的script標(biāo)簽中,否則JavaScript解釋器因?yàn)椴荒軌蜃R(shí)別這些合法的JavaScript代碼,而作為普通的字符串顯示在頁面文檔中。例如,下面的代碼就會(huì)把JavaScript代碼顯示出來,而不是執(zhí)行它。
復(fù)制代碼
代碼如下:
document.write('f();');
document.write('function f(){');
document.write('alert(1);');
document.write(');');
但是,通過document.write()方法輸出腳本并執(zhí)行也存在一定的風(fēng)險(xiǎn),因?yàn)椴煌琂avaScript引擎對其執(zhí)行順序不同,同時(shí)不同瀏覽器在解析時(shí)也會(huì)出現(xiàn)Bug。
? 問題一,找不到通過document.write()方法導(dǎo)入的外部JavaScript文件中聲明的變量或函數(shù)。例如,看下面示例代碼。
復(fù)制代碼
代碼如下:
document.write('script
type="text/javascript" src=""
/script');
document.write('script type="text/javascript"');
document.write('alert(n);'); // IE提示找不到變量n
document.write('/script');
alert(n+1); // 所有瀏覽器都會(huì)提示找不到變量n
外部JavaScript文件(test.js)的代碼如下:
復(fù)制代碼
代碼如下:
var n =
1;
分別在不同瀏覽器中進(jìn)行測試,會(huì)發(fā)現(xiàn)提示語法錯(cuò)誤,找不到變量n。也就是說,如果在JavaScript代碼塊中訪問本代碼塊中使用document.write()方法輸出的腳本中導(dǎo)入的外部JavaScript文件所包含的變量,會(huì)顯示語法錯(cuò)誤。同時(shí),如果在IE瀏覽器中,不僅在腳本中,而且在輸出的腳本中也會(huì)提示找不到輸出的導(dǎo)入外部JavaScript文件的變量(表述有點(diǎn)長和繞,不懂的讀者可以嘗試運(yùn)行上面代碼即可明白)。
? 問題二,不同JavaScript引擎對輸出的外部導(dǎo)入腳本的執(zhí)行順序略有不同。例如,看下面示例代碼。
復(fù)制代碼
代碼如下:
script type="text/javascript"
document.write('script type="text/javascript"
src=""
/script');
document.write('script type="text/javascript"');
document.write('alert(2);')
document.write('alert(n+2);');
document.write('/script');
/script
script type="text/javascript"
alert(n+3);
/script
外部JavaScript文件(test1.js)的代碼如下所示。
復(fù)制代碼
代碼如下:
var n = 1;
alert(n);
在IE瀏覽器中的執(zhí)行順序如圖1-6所示。
圖1-6 IE 7瀏覽器的執(zhí)行順序和提示的語法錯(cuò)誤
在符合DOM標(biāo)準(zhǔn)的瀏覽器中的執(zhí)行順序與IE瀏覽器不同,且沒有語法錯(cuò)誤,如圖1-7所示的是在Firefox 3.0瀏覽器中的執(zhí)行順序。
圖1-7 Firefox 3瀏覽器的執(zhí)行順序和提示的語法錯(cuò)誤
解決不同瀏覽器存在的不同執(zhí)行順序,以及可能存在Bug。我們可以把凡是使用輸出腳本導(dǎo)入的外部文件,都放在獨(dú)立的代碼塊中,這樣根據(jù)上面介紹的JavaScript代碼塊執(zhí)行順序,就可以避免這個(gè)問題。例如,針對上面示例,可以這樣設(shè)計(jì):
復(fù)制代碼
代碼如下:
script type="text/javascript"
document.write('script type="text/javascript"
src=""/script');
/script
script type="text/javascript"
document.write('script type="text/javascript"');
document.write('alert(2);') ; // 提示2
document.write('alert(n+2);'); // 提示3
document.write('/script');
alert(n+3); // 提示4
/script
script type="text/javascript"
alert(n+4); // 提示5
/script
這樣在不同瀏覽器中都能夠按順序執(zhí)行上面代碼,且輸出順序都是1、2、3、4和5。存在問題的原因是:輸出導(dǎo)入的腳本與當(dāng)前JavaScript代碼塊之間的矛盾。如果單獨(dú)輸出就不會(huì)發(fā)生沖突了。
學(xué)javascript的話確實(shí)有C語言基礎(chǔ)比較好,因?yàn)閖avascript從C-minus發(fā)展到ECMAscript,最終才是javascript,但是javascript的難點(diǎn)不在它的語法上,而是在他的瀏覽器兼容性上,這點(diǎn)是萬惡的微軟搞出來的。javascript和C的難點(diǎn)是不一致的,所以沒必要去學(xué)C語言。javascript要記住的東西非常多,而且條例不是很清楚,一般感覺比C語言用起來還麻煩。
既然做web前端的話,美工比javascript重要的多,畢竟有時(shí)候前端代碼都有現(xiàn)成的模板可以使用。相比之下javascript很多代碼都是通過后臺(tái)腳本直接嵌入到html頁面中的,比如Ajax代碼等。所以前端的話,初期只要會(huì)dom編程即可,能看懂框架代碼,慢慢理解就是了。
最難的部分是CSS,布局這點(diǎn)比javascript難的多,瀏覽器兼容性更令人傷心,畢竟javascript還有jquery等框架可以使用,但是css就沒這么幸運(yùn)了,除了某些css屬性可以通過jquery等框架屏蔽兼容之外,必須要手動(dòng)調(diào)試。
反正到最后你都必須精通HTML+CSS+javascript,內(nèi)容很少,但是很雜論,作為吃飯的工具,你不得不精通。甚至到最后你還得回后臺(tái)代碼才行比如,PHP 、java、C#等,因?yàn)閱螁问亲銮岸说暮苌俚?,大部分公司都是混合前后臺(tái)的,除了某些大公司,專門找美術(shù)專業(yè)的做前臺(tái)設(shè)計(jì)。
單做添加容易點(diǎn),清除會(huì)有許多問題的,下面的代碼調(diào)試通過,缺點(diǎn)是如果沒有添加123,只要輸入的內(nèi)容后面有123,點(diǎn)刪除的時(shí)侯也會(huì)被刪除,你試試看吧:
htmlhead
script language=javascript
function f_add(s){
text1.value+=s;
}
function f_del(s){
i=text1.value.lastIndexOf(s);
if (i=0) text1.value=text1.value.substr(0,i);
}
/script
/head
body
input type=text name=text1 value='abc'
button onclick="f_add('123');"添加123/button
button onclick="f_del('123');"刪除123/button
/body