作用域鏈中變量的使用原則
- 在作用域鏈中使用(讀取/設(shè)置)變量的時(shí)候, 首先在當(dāng)前作用域鏈中查找, 找到就直接使用
- 如果沒(méi)有找到, 就去上一級(jí)作用域鏈中查找, 直到0級(jí)作用域
閉包
-
一般情況下作用域: 內(nèi)層作用域可以訪(fǎng)問(wèn)外層作用域, 反之不行
function f1(){ var n=999; function f2(){ alert(n); // 999 } } -
有時(shí)候需要從外層作用域訪(fǎng)問(wèn)內(nèi)層作用域
-
直接return, 一次性獲取數(shù)據(jù), 每次獲取的不是同一份數(shù)據(jù)(變量創(chuàng)建后使用后就銷(xiāo)毀了)
function f1(){ var n=999; function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999 -
閉包技術(shù): 可以間接訪(fǎng)問(wèn)封閉空間私有數(shù)據(jù)的方法
- 閉包就是對(duì)直接return的數(shù)據(jù)進(jìn)行包裝(函數(shù))
-
-
閉包獲取數(shù)據(jù)和設(shè)置數(shù)據(jù)
- 判斷不傳形參的情況, 形參和變量不能同名 (同名的話(huà), 形參在調(diào)用賦值時(shí), 會(huì)先從當(dāng)前作用域找同名變量)
閉包的好處
- 獲取數(shù)據(jù)只能通過(guò)指定的方法(接口)
- 在設(shè)置數(shù)據(jù)的時(shí)候更加安全, 可以做一些校驗(yàn)工作
- 延長(zhǎng)變量的生命周期
setTimeout和閉包的執(zhí)行
//第一種寫(xiě)法
for(var i=0; i<3; i++){
(function(index){
setTimeout(function(){
console.log(index+'+++');
},0);
})(i);
}
//第二種寫(xiě)法
for(var i=0; i<3; i++){
setTimeout((function(index){
return function(){
console.log(index+'----');
}
})(i),0);
}
//第三種方法
for(let i=0; i<3; i++){
setTimeout(function(){
console.log(i+'----');
},1000);
}
div事件和閉包
-
JS的任務(wù)
- 渲染任務(wù)
- 代碼的主要任務(wù)
- 事件性的任務(wù)(點(diǎn)擊,定時(shí)器..)
-
JS是單線(xiàn)程
- 進(jìn)程: 正在運(yùn)行的應(yīng)用程序 (工廠)
- 線(xiàn)程: 進(jìn)程中用來(lái)執(zhí)行任務(wù)的(工人),一個(gè)線(xiàn)程同一時(shí)間只能執(zhí)行一個(gè)任務(wù)
- 串行執(zhí)行: 多個(gè)任務(wù)一個(gè)一個(gè)的按順序執(zhí)行
- 并發(fā)執(zhí)行: 多個(gè)任務(wù)同時(shí)執(zhí)行
- 多程線(xiàn):多條線(xiàn)程
- 多線(xiàn)程的原理: 1s = 1萬(wàn)個(gè)0.0001s cpu在多個(gè)任務(wù)之間來(lái)回的快速切換,造成多個(gè)任務(wù)同時(shí)執(zhí)行的假象
//JS單線(xiàn)程 先循環(huán)完 再觸發(fā)點(diǎn)擊事件時(shí) i遍歷完自加1變成5了--所以當(dāng)點(diǎn)擊div時(shí)變成5了
for (var i = 0; i < divs.length; i++) {
divs[i].onclick = function () {
console.log('點(diǎn)擊了第' + i + '個(gè)div');
}
}
//方法一:閉包解決拿到i的值
for (var i = 0; i < divs.length; i++) {
(function (j) {
divs[j].onclick = function () {
console.log('點(diǎn)擊了第' + j+ '個(gè)div');
}
})(i);
}
//方法二
for (var i = 0; i < divs.length; i++) {
divs[i].onclick = (function (j) {
return function () {
console.log('點(diǎn)擊了第' + j + '個(gè)div');
}
})(i);
}
函數(shù)的特殊性
- 特殊性(特點(diǎn)): 函數(shù)本身是對(duì)象, 且對(duì)象可以提供作用域
- 函數(shù)可以在運(yùn)行時(shí)動(dòng)態(tài)的創(chuàng)建, 還可以在程序執(zhí)行過(guò)程中創(chuàng)建
- 函數(shù)可以賦值給變量, 可以被擴(kuò)展, 甚至刪除
- 函數(shù)可以作為其他函數(shù)的參數(shù)/返回值
- 函數(shù)可以擁有自己的屬性和方法
- 注意
-
{}塊在JS中不會(huì)創(chuàng)建作用域, 哪怕是if或者是while語(yǔ)句中使用var關(guān)鍵字申明的變量也并非局部變量, 函數(shù)是可以通過(guò)()調(diào)用并執(zhí)行對(duì)象
-
- 函數(shù)是第一類(lèi)型對(duì)象
函數(shù)可以向普通對(duì)象一樣, 作為函數(shù)的參數(shù) | 賦值給變量(函數(shù)表達(dá)式) | 作為函數(shù)的返回值返回
-
fun.name函數(shù)名可以獲取, 但不能修改//函數(shù)作為參數(shù)傳遞 setTimeout(function () { console.log(1); },100); //函數(shù)作為返回值 function func() { return function () { console.log("demo"); } } var f = func(); f(); //demo //函數(shù)賦值給變量 var a = function(){} a(); //直接通過(guò)變量的名稱(chēng)調(diào)用函數(shù)
回調(diào)函數(shù)
- 定義: 把一個(gè)函數(shù)作為其他函數(shù)的參數(shù)
- 把函數(shù)作為另一個(gè)函數(shù)的參數(shù)
//01 提供一個(gè)對(duì)象,該對(duì)象中永遠(yuǎn)showName方法
var obj = {
name:"默認(rèn)的名字",
age:30,
showName:function () {
console.log(this.name);
},
showAge:function () {
console.log(this.age);
}
};
//02 提供一個(gè)函數(shù),該函數(shù)接受一個(gè)參數(shù)(函數(shù)引用)
function demo(callBack,callBack_obj) {
//處理第一個(gè)參數(shù)傳遞對(duì)象方法字符串的形式
if(typeof callBack == 'string') {
callBack = callBack_obj[callBack];
}
if (typeof callBack == 'function') {
callBack.call(callBack_obj);
}
}
//demo(obj.showName,obj);
//demo(obj.showAge,obj);
//傳遞字符串和對(duì)象來(lái)進(jìn)行調(diào)用
demo("showName",obj);
//(01)以上代碼傳入兩個(gè)參數(shù),分別為具體的回調(diào)函數(shù),和該回調(diào)函數(shù)所屬的對(duì)象
//(02)該函數(shù)的參數(shù)接受兩種方式的回調(diào)傳遞(一種是直接傳遞函數(shù)引用,一種是直接以字符串的方式傳遞對(duì)象方法的字符串)
//(03)在函數(shù)內(nèi)部對(duì)傳入的回調(diào)參數(shù)做處理,修正this的問(wèn)題
- 函數(shù)作為返回值
- 使用閉包實(shí)現(xiàn)一個(gè)計(jì)數(shù)器(在該示例中setup函數(shù)的返回值為一個(gè)函數(shù))
- 通過(guò)調(diào)用返回值(一個(gè)函數(shù)),可以操作setup函數(shù)中的變量
<script>
var setup = function () {
var count = 0;
return function () {
return count ++;
}
}
var next = setup();
console.log(next()); //0
console.log(next()); //1
console.log(next()); //2
</script>
惰性函數(shù)
-
定義: 函數(shù)真正的內(nèi)容需要執(zhí)行一次函數(shù)才能確定, 實(shí)現(xiàn)自我更新
function foo() { console.log("foo!"); //函數(shù)是引用型數(shù)據(jù), foo的存儲(chǔ)地址被重新定義了 foo = function () { console.log("new foo!"); } } //函數(shù)的調(diào)用 //foo(); //foo! //foo(); //new foo! 應(yīng)用場(chǎng): 函數(shù)有一些初始化的準(zhǔn)備工作要做,且只需要執(zhí)行一次的情況。
-
注意點(diǎn)
- 在函數(shù)上添加的屬性或方法, 自我更新后無(wú)法訪(fǎng)問(wèn)
-
把惰性函數(shù)賦值給變量, 以變量的(對(duì)象的方法)方式來(lái)調(diào)用, 不會(huì)更新(調(diào)用仍然是同一份數(shù)據(jù))
惰性函數(shù)以對(duì)象的形式訪(fǎng)問(wèn).png
惰性函數(shù)賦值給變量.png
即時(shí)函數(shù)
-
定義: 在函數(shù)定義之后立即執(zhí)行該函數(shù)。
//第一種寫(xiě)法 (function () { console.log("即時(shí)函數(shù)的第一種寫(xiě)法"); })(); //第二種寫(xiě)法 ;(function () { console.log("即時(shí)函數(shù)的第二種寫(xiě)法"); })(); //補(bǔ)充寫(xiě)法 (function (a) { console.log(a); }(20)); +function (b) { console.log(b); }(30); -function (b) { console.log(b); }(40); -
模式組成
- 使用函數(shù)表達(dá)式來(lái)定義函數(shù)(匿名函數(shù), 不能使用函數(shù)聲明方式)
- 在函數(shù)表達(dá)式末尾添加一組(), 表示立即執(zhí)行當(dāng)前函數(shù)
- 將整個(gè)函數(shù)包裝在()中, 有兩種方式
-
作用
- 用來(lái)將所有的代碼包裝到當(dāng)前的作用域中,并且不會(huì)將任何的變量泄露到全局作用域中。
- js中沒(méi)有代碼塊作用域,而函數(shù)是js中唯一可以創(chuàng)建作用域的。
- 即時(shí)函數(shù)就是利用了函數(shù)創(chuàng)建作用域這一點(diǎn),來(lái)實(shí)現(xiàn)對(duì)一些需要封裝且不允許外部訪(fǎng)問(wèn)的操作。
-
優(yōu)點(diǎn)
- 不會(huì)產(chǎn)生全局變量,在即時(shí)函數(shù)內(nèi)部定義的所有變量都僅僅只是該函數(shù)的局部變量,不會(huì)造成全局變量污染問(wèn)題。
- 具有更好的封裝性,外部無(wú)法訪(fǎng)問(wèn)到該函數(shù)內(nèi)部的數(shù)據(jù)。
-
即時(shí)函數(shù)的傳參和返回值
//01 接受參數(shù) (function (str) { console.log(str); //hello })("hello"); //02 提供返回值并賦值給新的變量 var foo = (function () { return 2 + 1; })(); console.log(foo); //3
即時(shí)對(duì)象初始化
- 結(jié)構(gòu)特征
- 提供一個(gè)對(duì)象, 在該對(duì)象內(nèi)部提供一個(gè)init初始化方法
- 使用()把對(duì)象包裝起來(lái)(讓字面量變成表達(dá)式)
- 然后隨即調(diào)用init方法, 完成初始化操作
- 基本結(jié)構(gòu)
- 即時(shí)對(duì)象初始化:
({init: function(){}}).init();
- 即時(shí)對(duì)象初始化:
- 模式優(yōu)點(diǎn)
- 在執(zhí)行一次性的初始化任務(wù)時(shí)保護(hù)全局的命名空間
({
name:"張三",
age:23,
getDescript:function () {
console.log("名字:" + this.name + "年齡:" + this.age);
},
//注意:在對(duì)象中訪(fǎng)問(wèn)對(duì)象的屬性和方法都需要使用this.前綴
init:function () {
this.getDescript();
//其他的初始化處理
}
}).init();
設(shè)計(jì)模式: 為了解決開(kāi)發(fā)中遇到的一類(lèi)問(wèn)題而提出的一套方法
- 要求: 一般一套系統(tǒng)需要設(shè)計(jì)模式
- 來(lái)源: 建筑行業(yè)
- 工廠模式核心
- 提供一個(gè)父構(gòu)造函數(shù)-->開(kāi)了一家工廠
- 設(shè)置父構(gòu)造函數(shù)的原型對(duì)象-->產(chǎn)品公共東西
- 在父構(gòu)造函數(shù)上提供一個(gè)靜態(tài)的工廠方法-->生產(chǎn)產(chǎn)品
- 接受傳入的參數(shù)
- 判斷是否支持生產(chǎn)
- 設(shè)置子構(gòu)造函數(shù)的原型對(duì)象是父構(gòu)造函數(shù)的一個(gè)實(shí)例(原型鏈繼承)
- 利用子構(gòu)造函數(shù)創(chuàng)建對(duì)象并且返回
- 定制合作伙伴
- 利用父構(gòu)造函數(shù)的靜態(tài)工廠方法創(chuàng)建對(duì)象
- 作用
- 通過(guò)統(tǒng)一的方法/接口創(chuàng)建對(duì)象, 并且根據(jù)不同的類(lèi)型創(chuàng)建不同的對(duì)象, 便于代碼的維護(hù)和擴(kuò)展

