js高級筆記

>undefined與null的區(qū)別

undefined? 代表已經(jīng)定義,但未賦值

null? 代表已經(jīng)定義并且賦值,只是值為null

>什么時候給變量賦值為null

- 初始賦值,表明將要為一個變量賦值,使之成為一個對象

- 結(jié)束前,讓某個變量指向的對象成為垃圾對象(被垃圾回收器回收)

>什么是函數(shù)?

- 實現(xiàn)特定功能的n條語句的封裝體

- 只有函數(shù)是可以執(zhí)行的,其他類型的數(shù)據(jù)不能執(zhí)行

>為什么要用函數(shù)?

- 提高代碼的復(fù)用

- 便于閱讀交流

>如何定義函數(shù)?

- 函數(shù)聲明 function fn (){}

- 表達(dá)式 var obj = function(){};

>如何調(diào)用(執(zhí)行)函數(shù)?

- test():直接調(diào)用

- obj.test():通過對象調(diào)用

- new test():new調(diào)用

- test.call/apply(obj):臨時讓test成為obj的方法進(jìn)行調(diào)用

>什么函數(shù)才是回調(diào)函數(shù)?

1).你定義的

2).你沒有調(diào)用

3).但最終它執(zhí)行了

>常見的回調(diào)函數(shù)

- dom事件回調(diào)函數(shù)(onclick 等等)

- 定時器回調(diào)函數(shù)? (延時定時器,循環(huán)定時器)

- ajax請求回調(diào)函數(shù)

- 生命周期回調(diào)函數(shù)

>什么叫IIFE

1)理解

立即執(zhí)行函數(shù)表達(dá)式

2)作用

- 隱藏實現(xiàn)(可以將函數(shù),變量聲明放入其中,使其只在局部作用)

- 不會污染外部(全局)命名空間

( function( ){

? ? ? ? var obj = xxx;

} )( )

>函數(shù)中的this

1)this是什么?

- 任何函數(shù)本質(zhì)上都是通過某個對象來調(diào)用的,如果沒有直接指定就是window

- 所有函數(shù)內(nèi)部都有一個變量this

- 它的值是調(diào)用函數(shù)的當(dāng)前對象

2)如何確定thie的值?

- test( ): // window

- p.test( ): // p

- var p = new test( )://新創(chuàng)建的對象p

- p.call(obj): // obj

>函數(shù)的prototype屬性

- 每個函數(shù)都有一個prototype屬性,它默認(rèn)指向一個Object空對象(即稱為原型對象)

- 原型對象中有一個屬性constructor,它指向函數(shù)對象

? 給原型對象添加屬性(一般都是方法)

- 作用:函數(shù)的所有實例對象自動擁有原型中的屬性(方法)

function Fun ( ) {? } //聲明一個Fun函數(shù)(構(gòu)造函數(shù))

Fun.prototype.test=function ( ) { //為Fun的原型對象添加test方法

console.log( " abc " );

};

var fun = new Fun( ); //新建一個Fun函數(shù)的實例

fun.test( ); //返回abc

>顯式原型與隱式原型

- 每個函數(shù)function都有一個prototype,即顯式原型(屬性)

- 每個實例對象都有一個__proto__,成為隱式原型(屬性)

- 對象的隱式原型的值為其對應(yīng)構(gòu)造函數(shù)的顯式原型的值

- 內(nèi)存結(jié)構(gòu)(圖)

- 總結(jié)

* 函數(shù)的prototype屬性:在定義時自動添加的,默認(rèn)值是一個空Object實例對象

* 對象的__proto__屬性:創(chuàng)建對象時自動添加的,默認(rèn)值為其構(gòu)造函數(shù)的prototype屬性值

* 程序員能直接操作顯示原型,但不能直接操作隱式原型(ES6之前)

>原型鏈

* 訪問一個對象屬性時,先在自身屬性中查找,找到返回,如果沒有,再沿著__proto__這條鏈向上查找,找到返回,如果最終沒有找到,返回undefined

* 別名:隱式原型連

* 作用:查找對象的屬性(方法)

* 補充:

1)函數(shù)的顯式原型指向的對象默認(rèn)是空Object實例對象(但Object不滿足)

2)所有函數(shù)都是Function的實例(包含F(xiàn)unction也是其自身的實例)

3)Object的原型對象時原型鏈的盡頭

* 原型鏈的屬性問題

1)讀取對象的屬性值時,會自動到原型鏈中查找

2)設(shè)置對象的屬性值時,不會查找原型鏈,如果當(dāng)前對象沒有此屬性值,直接添加此屬性并設(shè)置其值

3)方法一般定義在原型中,屬性一般通過構(gòu)造函數(shù)定義在對象本身上

>instanceof

- 如何判斷

1)表達(dá)式:A instanceof B

2)如果B函數(shù)的顯示原型對象,在A對象的原型鏈上,返回true,否則返回false

- Function是通過new自己產(chǎn)生的實例? ( var Function = new Function( ); )

>變量提升與函數(shù)提升

- 變量聲明提升

* 通過var定義(聲明)的變量,在定義語句之前就可以訪問到

* 值:undefined

- 函數(shù)聲明提升

* 通過function聲明的函數(shù),在之前就可以直接調(diào)用

* 值:函數(shù)定義(對象)

>執(zhí)行上下文

- 代碼分類(位置)

* 全局代碼

* 函數(shù)(局部)代碼

- 全局執(zhí)行上下文

* 在執(zhí)行全局代碼前將window確定為全局執(zhí)行上下文

* 對全局?jǐn)?shù)據(jù)進(jìn)行預(yù)處理

1)var 定義的全局變量 ==>undefined,添加為window的屬性

2)function聲明的全局函數(shù)==>賦值(fun),添加為window的方法

3)this==>賦值(window)

* 開始執(zhí)行全局代碼

- 函數(shù)執(zhí)行上下文

* 在調(diào)用函數(shù),準(zhǔn)備執(zhí)行函數(shù)體之前,創(chuàng)建對應(yīng)的函數(shù)執(zhí)行上下文對象

* 對局部數(shù)據(jù)進(jìn)行預(yù)處理

1)形參變量==>賦值(實參)==>添加為執(zhí)行上下文的屬性

2)arguments==>賦值(實參列表),添加為執(zhí)行上下文的屬性

3)var 定義的局部變量==>undefined,添加為執(zhí)行上下文的屬性

4)function聲明的函數(shù)==>賦值(fun),添加為執(zhí)行上下文的方法

5)this==>賦值(調(diào)用函數(shù)的對象)

* 開始執(zhí)行函數(shù)體代碼

>執(zhí)行上下文棧

* 在全局代碼執(zhí)行前,JS引擎就會創(chuàng)建一個棧來存儲管理所有的執(zhí)行上下文對象

* 在全局執(zhí)行上下文(window)確定后,將其添加到棧中(壓棧)

* 在函數(shù)執(zhí)行上下文創(chuàng)建后,將其添加到棧中(壓棧)

* 在當(dāng)前函數(shù)執(zhí)行完后,將棧頂?shù)膶ο笠瞥ǔ鰲#?/p>

* 當(dāng)所有的代碼執(zhí)行完后,棧中只剩下window

>作用域與作用域鏈

- 理解: * 就是一塊“地盤”,一個代碼段所在的區(qū)域

* 它是靜態(tài)的(相對于上下文對象),在編寫代碼的時候就確定了

- 分類: * 全局作用域

* 函數(shù)作用域

* 沒有塊作用域(ES6有了)

- 作用:隔離變量,不同作用域下同名變量不會有沖突

- 區(qū)別:

1)區(qū)別1

* 全局作用域外,每個函數(shù)都會創(chuàng)建自己的作用域,作用域在定義函數(shù)的時候就已經(jīng)確定了,而不是在函數(shù)調(diào)用時

* 全局執(zhí)行上下文環(huán)境是在全局作用域確定之后,JS代碼馬上執(zhí)行之前創(chuàng)建

* 函數(shù)執(zhí)行上下文時在調(diào)用函數(shù)時,函數(shù)體代碼執(zhí)行之前創(chuàng)建

2)區(qū)別2

* 作用域是靜態(tài)的,只要函數(shù)定義好了就一直存在,且不會再變化

* 執(zhí)行上下文是動態(tài)的,調(diào)用函數(shù)時創(chuàng)建,函數(shù)調(diào)用結(jié)束時上下文環(huán)境就會自動釋放

3)聯(lián)系

* 執(zhí)行上下文(對象)是從屬于所在的作用域

* 全局上下文環(huán)境==>全局作用域

* 函數(shù)上下文環(huán)境==>對應(yīng)的函數(shù)作用域

>閉包

1)如何產(chǎn)生閉包

* 當(dāng)一個嵌套的內(nèi)部(子)函數(shù)引用了嵌套的外部(父)函數(shù)的變量(函數(shù))時,就產(chǎn)生了閉包

2)閉包到底是什么?

* 使用chrome調(diào)試查看

* 理解一:閉包時嵌套的內(nèi)部數(shù)據(jù)(絕大部分人)

* 理解二:包含被引用變量(函數(shù))的對象(極少數(shù)人)

* 注意:閉包存在于嵌套的內(nèi)部函數(shù)中

3)產(chǎn)生閉包的條件?

* 函數(shù)嵌套

* 內(nèi)部引用了外部函數(shù)的數(shù)據(jù)(變量/函數(shù))

* 調(diào)用了外部函數(shù)

4)閉包的作用

* 使函數(shù)內(nèi)部的變量在函數(shù)執(zhí)行完之后,仍然存活在內(nèi)存中(延長了局部變量的生命周期)

* 讓函數(shù)外部可以操作(讀寫)到函數(shù)內(nèi)部的數(shù)據(jù)(變量/函數(shù))

5)問題

* 函數(shù)執(zhí)行完后,函數(shù)內(nèi)部聲明的局部變量是否還存在?

答:一般是不存在,存在于閉包中的變量才可能存在

* 在函數(shù)外部能直接訪問函數(shù)內(nèi)部的局部變量嗎?

答:不能,但我們可以通過閉包讓外部操作它

>閉包的生命周期

- 產(chǎn)生:在嵌套內(nèi)部函數(shù)定義執(zhí)行完成時就產(chǎn)生了(不是在調(diào)用,僅僅是定義)

- 死亡:在嵌套的內(nèi)部函數(shù)成為垃圾對象時

>閉包的應(yīng)用

- 定義JS模塊

* 具有特定功能的JS文件

* 將所有的數(shù)據(jù)和功能都封裝在一個函數(shù)內(nèi)部(私有的)

* 只向外暴露一個包含n個方法的對象或函數(shù)

* 模塊的使用者,只需要通過模塊暴露的對象調(diào)用方法來實現(xiàn)對應(yīng)的功能

>閉包的缺點

1)缺點:

* 函數(shù)執(zhí)行完后,函數(shù)內(nèi)的局部變量沒有釋放,占用內(nèi)存時間會變長

* 容易造成內(nèi)存泄漏

2)解決:

* 能不用閉包就不用閉包(很難不會去用到閉包,所以及時釋放就好)

* 及時釋放

>內(nèi)存溢出與內(nèi)存泄漏

1)內(nèi)存溢出:

* 一種程序運行出現(xiàn)的錯誤

* 當(dāng)程序員需要的內(nèi)存超過了剩余的內(nèi)存時,就出現(xiàn)內(nèi)存溢出的錯誤

2)內(nèi)存泄漏:

* 占用的內(nèi)存沒有及時釋放

* 內(nèi)存泄漏積累多了就容易導(dǎo)致內(nèi)存溢出

* 常見的內(nèi)存泄漏:

- 意外的全局變量(例如函數(shù)中聲明的變量沒有帶 var )

- 沒有及時清理的計時器或回調(diào)函數(shù)

- 閉包

>對象創(chuàng)建模式

1)Object構(gòu)造函數(shù)模式

* 套路:先創(chuàng)建空Object對象,再動態(tài)添加屬性/方法

* 適用場景:起始時不確定對象內(nèi)部數(shù)據(jù)

* 問題:語句太多

例:

var p = new Object( );

p.name = "tom";

p.age = 12;

p.setName = function( ){

this.name = name

}

2)對象字面量模式:

* 套路:使用{ }創(chuàng)建對象,同時制定屬性/方法

* 適用場景:起始時對象內(nèi)部數(shù)據(jù)是確定的

* 問題:如果創(chuàng)建多個對象,有重復(fù)代碼

例:

var p = {

name : "tom",

age: 12,

setName : function( name ){

this.name = name;

}

}

3)工廠模式:

* 套路:通過工廠函數(shù)動態(tài)創(chuàng)建對象并返回

* 適用場景:需要創(chuàng)建多個對象

* 問題:對象沒有一個具體的類型,都是Object類型

例:

function createPerson( name , age ){

var obj = {

name : name,

age : age,

setName : function ( name ){

this.name = name;

}

}

return obj;

}

createPerson( "jack","12");

createPerson("bob","18");

4)自定義構(gòu)造函數(shù)模式

5)構(gòu)造函數(shù)+原型的組合模式

>線程與進(jìn)程

1)進(jìn)程:

* 程序的一次執(zhí)行,它占有一片獨有的內(nèi)存空間

* 可以通過windows任務(wù)管理器查看進(jìn)程

2)線程:

* 是進(jìn)程內(nèi)的一個獨立執(zhí)行單元

* 是程序執(zhí)行的一個完整流程

* 是CPU的最小調(diào)度單元

3)關(guān)系:

* 一個進(jìn)程至少有一個線程(主線程)

* 程序是在某個進(jìn)程中的某個線程執(zhí)行的

>瀏覽器內(nèi)核模塊組成

1)主線程

* js引擎模塊:負(fù)責(zé)js程序的編譯與運行

* html,css文檔解析模塊:負(fù)責(zé)頁面文本的解析

* DOM/CSS模塊:負(fù)責(zé)dom/css在內(nèi)存中的相關(guān)處理

* 布局和渲染模塊:負(fù)責(zé)頁面的布局和效果的繪制(內(nèi)存中的對象)

2)分線程

* 定時器模塊:負(fù)責(zé)定時器的管理

* 事件響應(yīng)模塊:負(fù)責(zé)時間的管理

* 網(wǎng)絡(luò)請求模塊:Ajax請求

>js線程

* js是單線程執(zhí)行的(回調(diào)函數(shù)也是在主線程)

* H5提出了實現(xiàn)多線程的方法:Web Workers

* 只能是主線程更新界面

>定時器問題

* 定時器并不真正完全定時

* 如果在主線程執(zhí)行了一個長時間的操作,可能導(dǎo)致延時才處理

>事件處理機(jī)制(圖)

- 代碼分類

* 初始化執(zhí)行代碼:包含綁定dom事件監(jiān)聽,設(shè)置定時器,發(fā)送ajax請求的代碼

* 回調(diào)執(zhí)行代碼:處理回調(diào)邏輯

- js引擎執(zhí)行代碼的基本流程

* 初始化代碼===>回調(diào)代碼

- 模型的2個重要組成部分:

* 事件的管理模塊

* 回調(diào)隊列

- 模型的運轉(zhuǎn)流程

* 執(zhí)行初始化代碼,將事件回調(diào)函數(shù)交給對應(yīng)的模塊管理

* 當(dāng)事件發(fā)生時,管理模塊會將回調(diào)函數(shù)及其數(shù)據(jù)添加到回到隊列中

* 只有當(dāng)初始化代碼執(zhí)行完成(可能需要一定的時間),才會遍歷讀取回調(diào)隊列中的回調(diào)函數(shù)并執(zhí)行

>H5 Web Workers

* 可以讓js在分線程執(zhí)行

* Worker

* 問題

- worker內(nèi)代碼不能操作DOM更新UI

- 不是每個瀏覽器都支持這個新特性

- 不能跨域加載JS

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容