
一、概述
JavaScript是世界上最流行的腳本語言末购,是一種運行在瀏覽器中的解釋型的編程語言,能夠?qū)崿F(xiàn)跨平臺虎谢、跨瀏覽器盟榴。雖然只是十多天時間的產(chǎn)物,并且有很多的缺陷和陷阱婴噩,但也造就了JavaScript的靈活和強大擎场。隨著Node.js的興起,JavaScript已經(jīng)從單純實現(xiàn)前端互動几莽,發(fā)展到可以全棧實現(xiàn)整個應(yīng)用迅办。尤其是在移動互聯(lián)網(wǎng)蓬勃發(fā)展以及應(yīng)用追求極致用戶體驗的今天,JavaScript更是必須要重視和掌握的章蚣。
二站欺、變量
1、變量的聲明
使用var關(guān)鍵字進(jìn)行變量的聲明纤垂,聲明的同時也可以進(jìn)行賦值矾策。變量的聲明只能有一次,但賦值可以有多次洒忧。如果只聲明變量蝴韭,但是變量沒有被賦值,此時變量的值為undefined熙侍。
var s = "Hello";
由于JavaScript屬于動態(tài)語言榄鉴,所以在定義變量時,不需要指定變量的類型蛉抓∏斐荆可以把任意數(shù)據(jù)類型賦值給變量,同一個變量可以使用不同的數(shù)據(jù)類型反復(fù)賦值巷送。
2驶忌、變量的提升
根據(jù)JavaScript的規(guī)則,變量的聲明會被提升,但是變量的初始化并不會被提升付魔。函數(shù)外聲明的變量聊品,會被提升到文檔頂部。函數(shù)內(nèi)聲明的變量几苍,會被提升到函數(shù)頂部翻屈。
function f() {
var x = 1 + y;
alert(x);
var y = 2;
}
alert(x);
如果變量在函數(shù)內(nèi)沒有聲明,該變量會被提升為全局變量妻坝。
function f() {
x = 1;
}
alert(x);
3伸眶、變量的作用域
如果變量在函數(shù)內(nèi)聲明,則該變量的作用域為整個函數(shù)體刽宪,在函數(shù)外不可訪問厘贼,屬于局部變量。
function f() {
var x = 1;
}
alert(x);
函數(shù)可以嵌套圣拄,內(nèi)部函數(shù)可以訪問外部函數(shù)定義的變量嘴秸,反之則不可。
function outer() {
var x = 1;
function inner() {
var y = x + 1;
alert(y);
}
var z = y + 1;
alert(z);
}
如果內(nèi)部函數(shù)與外部函數(shù)定義了相同的變量售担,根據(jù)就近原則赁遗,內(nèi)部函數(shù)的變量會覆蓋外部函數(shù)的變量。
function outer() {
var x = 1;
function inner() {
var x = 2;
alert(x);
}
}
三族铆、函數(shù)
1岩四、函數(shù)的定義
定義函數(shù)有兩種方式:聲明和表達(dá)式。
1.1 函數(shù)聲明
function function_name(parameters) {
......
}
函數(shù)聲明后不會馬上執(zhí)行哥攘,只有被調(diào)用的時候才會執(zhí)行剖煌。
1.2 函數(shù)表達(dá)式
var f = function (parameters) {
......
};
f(parameters);
將函數(shù)存儲在變量中,之后可以通過變量名來調(diào)用逝淹,而不需要函數(shù)名稱耕姊。
2、函數(shù)的參數(shù)
函數(shù)有個內(nèi)置的對象arguments栅葡,包含了函數(shù)調(diào)用的所有參數(shù)茉兰。
參數(shù)有兩種傳遞方式:值傳遞和引用傳遞。
2.1 值傳遞
函數(shù)只是獲取參數(shù)值欣簇,如果修改參數(shù)的值规脸,不會改變參數(shù)的原始值,在函數(shù)外是不可見的熊咽。
2.2 引用傳遞
函數(shù)獲得的是對象的引用莫鸭,在函數(shù)內(nèi)部修改對象屬性時,會改變屬性的原始值横殴,在函數(shù)外可見被因。
3、函數(shù)的調(diào)用
函數(shù)可以通過四種方式進(jìn)行調(diào)用。
3.1 自我調(diào)用
函數(shù)表達(dá)式梨与,如果后面緊跟()堕花,則會自動自我調(diào)用。聲明的函數(shù)不能自我調(diào)用蛋欣。
(function () {
alert("Hello");
})();
3.2 作為函數(shù)被調(diào)用
當(dāng)函數(shù)沒有被其他對象調(diào)用時航徙,函數(shù)默認(rèn)是window全局對象的函數(shù)如贷。此時this的值是window全局對象陷虎。
function f() {
alert("Hello");
return this;
};
f();
3.3 作為方法被調(diào)用
可以將函數(shù)定義為對象的方法,該對象是函數(shù)的所有者杠袱。當(dāng)使用對象調(diào)用方法時尚猿,此時的this值指向調(diào)用函數(shù)的對象。
var obj = {
x : 1,
y : 2,
f : function () { return this.x + this.y;}
};
obj.f();
3.4 作為構(gòu)造函數(shù)被調(diào)用
如果使用new關(guān)鍵字楣富,實際是創(chuàng)建了一個新的對象凿掂。新對象會繼承構(gòu)造函數(shù)的屬性和方法。此時this值指向新創(chuàng)建的對象纹蝴。為了區(qū)分普通函數(shù)和構(gòu)造函數(shù)庄萎,約定構(gòu)造函數(shù)的首字母為大寫。
function F(x, y) {
this.x = x;
this.y = y;
};
var obj = new F(1, 2);
3.5 call和apply
函數(shù)是一個對象塘安,可以調(diào)用call或apply方法糠涛。此時this值指向方法傳遞的對象。
function f(x, y) {
return x+y;
};
arr = [1, 2];
f.call(obj, 1, 2);
f.apply(obj, arr);
call和apply方法的唯一區(qū)別就是前者傳遞整個參數(shù)列表兼犯,而后者傳遞一個參數(shù)數(shù)組忍捡。
4、閉包
內(nèi)嵌函數(shù)可以訪問上一層函數(shù)的變量切黔。閉包是可以訪問上一層函數(shù)作用域里變量的函數(shù)砸脊。如果上一層函數(shù)返回閉包函數(shù),那么就可以在上一層函數(shù)的外部訪問該函數(shù)的私有變量纬霞。利用閉包凌埂,可以實現(xiàn)調(diào)用公共方法,訪問私有變量诗芜。
此時返回的函數(shù)并沒有立刻執(zhí)行瞳抓,只有在調(diào)用返回函數(shù)時才真正執(zhí)行。因為返回函數(shù)不會馬上執(zhí)行绢陌,所以返回函數(shù)不要引用循環(huán)變量或后續(xù)會發(fā)生變化的變量挨下。否則,在真正執(zhí)行的時候脐湾,引用的變量可能已經(jīng)發(fā)生改變臭笆。
如果必須引用的話,可以再創(chuàng)建一個函數(shù),用該函數(shù)的參數(shù)綁定循環(huán)變量的值愁铺。這樣鹰霍,循環(huán)變量的值雖然發(fā)生了改變,但綁定到參數(shù)的值不會隨之改變茵乱。
四茂洒、對象
1、對象的定義
對象的定義有兩種方式瓶竭。
由若干鍵值對組成督勺,并將其賦值給一個變量。
var person = {
name : "sean",
age : "20",
sayHello : function() {
alert("Hello " + name);
}
};
person.sayHello();
使用函數(shù)定義對象斤贰,然后創(chuàng)建新的對象實例智哀。
function person(name, age) {
this.name = name;
this.age = age;
};
var p = new person("sean", 20);
2、屬性和方法
由于JavaScript的對象是動態(tài)類型荧恍,所以可以給一個對象添加或刪除屬性瓷叫。當(dāng)訪問的屬性不存在時,會返回undefined送巡。如果要判斷一個屬性是否屬于某對象摹菠,可以使用in操作符。這里要注意的是骗爆,該屬性可能是對象繼承得來的次氨。如果要判斷一個屬性是否屬于某對象自身,可以使用hasOwnProperty方法淮腾。
3糟需、原型
雖然JavaScript可以面向?qū)ο缶幊蹋械膶ο蠖际菍嵗瘸粫^(qū)分類和實例的概念洲押。要想實現(xiàn)類的概念,就需要借助原型圆凰。
首先創(chuàng)建一個相當(dāng)于類概念的對象實例杈帐。
var person = {
name : "",
age : "",
sayHello : function() {
alert("Hello " + this.name);
}
};
然后創(chuàng)建一個新的對象實例,使其依賴這個原型专钉。
var sean = {
name : "sean"
};
sean.__prototype__ = person;
sean.sayHello();
也可以使用Object.create()方法挑童,傳入一個原型對象,并創(chuàng)建一個基于該原型的新對象跃须。
var sean = Object.create(person);
sean.name = "sean";
sean.sayHello();
4站叼、創(chuàng)建對象
JavaScript對每個創(chuàng)建的對象都會設(shè)置一個原型,指向該對象的原型對象菇民。除了直接創(chuàng)建一個對象外尽楔,還可以使用構(gòu)造函數(shù)來創(chuàng)建對象投储。使用構(gòu)造函數(shù)創(chuàng)建的對象,會從原型獲得一個constructor屬性阔馋,該屬性指向構(gòu)造函數(shù)本身玛荞。
5、原型鏈
當(dāng)訪問一個對象的屬性時呕寝,首先在當(dāng)前對象上查找該屬性勋眯。如果沒有找到,就到其原型對象上查找下梢。如果還沒有找到客蹋,就一直上溯到Object的原型對象。如果還沒有找到怔球,就返回undefined嚼酝。這樣就形成了一條原型鏈。
因為函數(shù)也是對象竟坛,所以函數(shù)也擁有原型鏈。首先是函數(shù)本身钧舌,然后是Function.prototype担汤,最后是Object.prototype。
6洼冻、繼承
繼承不僅僅是對象的屬性和方法的繼承崭歧,原型鏈也要體現(xiàn)出繼承關(guān)系。
首先撞牢,定義新的構(gòu)造函數(shù)率碾,并在內(nèi)部調(diào)用希望繼承的構(gòu)造函數(shù),實現(xiàn)屬性和方法的繼承屋彪。
其次所宰,借助中間函數(shù),將新的構(gòu)造函數(shù)的原型指向繼承的構(gòu)造函數(shù)的原型畜挥,實現(xiàn)原型鏈繼承仔粥。
最后,將新的構(gòu)造函數(shù)的constructor屬性重新指向新的構(gòu)造函數(shù)蟹但。
7躯泰、瀏覽器對象
window對象不但是全局對象,還表示瀏覽器窗口华糖。
屬性innerWidth和innerHeight分別表示瀏覽器窗口的內(nèi)部寬度和高度麦向,即用于顯示網(wǎng)頁的凈寬高。屬性outerWidth和outerHeight分別表示瀏覽器窗口的整個寬度和高度客叉。
navigator對象表示瀏覽器的信息诵竭。屬性appName表示瀏覽器名稱景描。屬性appVersion表示瀏覽器版本。屬性language表示瀏覽器設(shè)置的語言秀撇。屬性platform表示操作系統(tǒng)類型超棺。屬性userAgent表示瀏覽器設(shè)定的User-Agent字符串。
screen對象表示屏幕的信息呵燕。屬性width表示屏幕寬度棠绘,單位是像素。屬性height表示屏幕高度再扭,單位是像素氧苍。屬性colorDepth表示顏色位數(shù)。
location對象表示當(dāng)前頁面的URL信息泛范。屬性href表示整個URL让虐。屬性protocal表示使用的協(xié)議。屬性host表示主機名罢荡。屬性port表示端口號赡突。屬性pathname表示訪問的路徑。屬性search表示查詢參數(shù)区赵。方法assign加載一個新頁面惭缰。方法reload重載當(dāng)前頁面。
document對象表示當(dāng)前頁面笼才。屬性title表示瀏覽器窗口的標(biāo)題漱受。屬性cookie獲取當(dāng)前頁面的Cookie。方法getElementById按照元素的id獲取一個DOM節(jié)點骡送。方法getElementByTabName按照元素的標(biāo)簽名稱獲取一組DOM節(jié)點昂羡。
history對象保存瀏覽器的歷史記錄。
五摔踱、DOM
當(dāng)頁面被加載時虐先,瀏覽器解析HTML文檔,并會創(chuàng)建頁面的文檔對象模型DOM昌渤。DOM是一個樹形結(jié)構(gòu)赴穗,通過操作DOM節(jié)點,可以訪問或改變文檔的所有元素膀息。針對DOM的操作主要有四種:查找般眉、更新、插入潜支、刪除甸赃。
1、查找
要想操作DOM節(jié)點冗酿,首先需要找到要操作的節(jié)點埠对。
-
通過id查找
調(diào)用document.getElementById方法查找指定id的元素络断。
-
通過標(biāo)簽名查找
調(diào)用document.getElementByTagName方法查找指定標(biāo)簽名的所有元素。
-
通過類名查找
調(diào)用document.getElementByClassName方法查找指定class的所有元素项玛。
Tips:要精確地定位DOM貌笨,可以先定位父節(jié)點,再逐步縮小范圍襟沮。
2锥惋、更新
定位好節(jié)點之后,就可以進(jìn)行更新操作开伏。
-
修改innerHTML屬性
不但可以修改一個DOM節(jié)點的文本內(nèi)容膀跌,還可以通過HTML片段修改DOM節(jié)點內(nèi)部的子樹。
-
修改innerText或textContent屬性
可以對字符串進(jìn)行HTML編碼固灵,保證無法設(shè)置任何HTML標(biāo)簽捅伤。這兩個屬性的區(qū)別是前者不返回隱藏元素的文本,而后者則返回所有文本巫玻。
-
修改style屬性
可以用來設(shè)置CSS樣式丛忆。如果是無效的屬性名,可以在JavaScript中使用駝峰式命名屬性大审。
3蘸际、插入
可以插入新的節(jié)點,從而改變DOM結(jié)構(gòu)徒扶。
-
appendChild方法
把一個子節(jié)點添加到父節(jié)點的最后一個子節(jié)點。如果子節(jié)點已經(jīng)存在根穷,會先從原來的位置刪除姜骡,然后再插入到新的位置。通常會新創(chuàng)建一個節(jié)點屿良,然后插入到指定位置圈澈,實現(xiàn)動態(tài)添加節(jié)點。
-
insertBefore方法
父節(jié)點會將新建的子節(jié)點插入到參照節(jié)點之前尘惧。
4康栈、刪除
可以刪除節(jié)點,從而改變DOM結(jié)構(gòu)喷橙。
-
removeChild方法
首先獲得要刪除的節(jié)點和它的父節(jié)點啥么,然后調(diào)用父節(jié)點的方法將其刪除。遍歷父節(jié)點的子節(jié)點并進(jìn)行刪除操作時贰逾,父節(jié)點的children屬性會在子節(jié)點發(fā)生變化時實時更新悬荣,需要特別注意。
六疙剑、異步處理
JavaScript語言是單線程的氯迂,一次只能完成一個任務(wù)践叠。好處是實現(xiàn)簡單,壞處是如果有任務(wù)耗時很長嚼蚀,其他的任務(wù)就必須得排隊等待禁灼,直到該任務(wù)完成。導(dǎo)致的結(jié)果就是造成瀏覽器無響應(yīng)轿曙,其他任務(wù)無法執(zhí)行弄捕,體驗極差。
因此拳芙,JavaScript語言分成兩種任務(wù)執(zhí)行模式:同步和異步察藐。所謂同步,就是指程序的執(zhí)行順序與任務(wù)的排列順序是一致的舟扎、同步的分飞。所謂異步,是指每個任務(wù)有一個或多個回調(diào)函數(shù)睹限,后一個任務(wù)無需等待前一個任務(wù)完成就可執(zhí)行譬猫,當(dāng)前一個任務(wù)完成后,執(zhí)行回調(diào)函數(shù)羡疗。這樣染服,程序的執(zhí)行順序與任務(wù)的排列順序是不一致的、異步的叨恨。
1柳刮、回調(diào)函數(shù)
這是異步處理最常用的的方法。
兩個同步執(zhí)行的函數(shù):
f1();
f2();
兩個異步執(zhí)行的函數(shù):
function f1(callback){
setTimeout(function () {
// f1的任務(wù)代碼
callback();
}, 1000);
}
f1(f2);
回調(diào)函數(shù)的優(yōu)點是簡單痒钝、容易理解秉颗。缺點是不利于閱讀和維護(hù)、高耦合送矩、流程混亂蚕甥,每個任務(wù)只能指定一個回調(diào)函數(shù)。
2栋荸、事件監(jiān)聽
采用事件驅(qū)動模式菇怀,由事件來決定要進(jìn)行的處理,而不是代碼的順序晌块。
為f1綁定一個事件爱沟,當(dāng)f1發(fā)生done事件,就執(zhí)行f2:
f1.on('done', f2);
執(zhí)行完成后摸袁,立即觸發(fā)done事件钥顽,從而開始執(zhí)行f2:
function f1(){
setTimeout(function () {
// f1的任務(wù)代碼
f1.trigger('done');
}, 1000);
}
事件監(jiān)聽的優(yōu)點是容易理解,可以綁定多個事件靠汁,每個事件可以指定多個回調(diào)函數(shù)蜂大,低耦合闽铐。缺點是流程不夠清晰。
3奶浦、發(fā)布/訂閱
與事件監(jiān)聽類似兄墅。某個任務(wù)執(zhí)行完成之后,會發(fā)布一個信號澳叉,其他任務(wù)可以訂閱這個信號隙咸,從而知道什么時候可以開始執(zhí)行。又稱為觀察者模式成洗。
訂閱信號:
jQuery.subscribe("done", f2);
發(fā)布信號:
function f1(){
setTimeout(function () {
// f1的任務(wù)代碼
jQuery.publish("done");
}, 1000);
}
取消訂閱:
jQuery.unsubscribe("done", f2);
可以了解存在多少信號五督、每個信號有多少訂閱者,從而監(jiān)聽程序的運行瓶殃。
4充包、Promises對象
該對象是CommonJS提出的一種規(guī)范,旨在為異步編程提供統(tǒng)一接口遥椿。
每一個異步任務(wù)返回一個Promises對象:
function f1(){
var dfd = $.Deferred();
setTimeout(function () {
// f1的任務(wù)代碼
dfd.resolve();
}, 500);
return dfd.promise;
}
該對象有一個then方法基矮,可以指定回調(diào)函數(shù):
f1().then(f2);
優(yōu)點是回調(diào)函數(shù)可以使用鏈?zhǔn)綄懛ǎ鞒糖逦诔。⑶胰绻粋€任務(wù)已經(jīng)完成家浇,再添加回調(diào)函數(shù),該回調(diào)函數(shù)會立刻執(zhí)行碴裙。缺點是編寫和理解比較困難钢悲。
參考資料: