JS難點同步異步和作用域與閉包及原型和原型鏈詳解
JS三座大山
同步異步
前端中只有兩個操作是異步的:
- 定時器異步執(zhí)行;
- ajax異步請求
編譯器解析+執(zhí)行代碼原理:
1.編譯器從上往下逐一解析代碼
2.判斷代碼是同步還是異步
- 同步:立即執(zhí)行
- 異步:不執(zhí)行。放入事件隊列池
3.等所有同步執(zhí)行完畢開始執(zhí)行異步
同步異步區(qū)別
api : 異步有回調(diào),同步?jīng)]有回調(diào)
性能 : 異步性能好(不阻塞線程) 同步會阻塞線程
順序 : 同步有序執(zhí)行,異步無序執(zhí)行
另:回調(diào)函數(shù):如果一個函數(shù)的參數(shù)是一個函數(shù),那么這個參數(shù)函數(shù)叫做回調(diào)函數(shù)
作用域、閉包
函數(shù)作用域鏈
- 只有
var
聲明的變量認的是函數(shù)作用域 - 只有函數(shù)才能開辟新的函數(shù)作用域
- 默認全局區(qū)域,我們稱之為0級作用域,在0級上聲明的函數(shù),會開一個新的作用域,我們稱之為1級作用域
- 在1級里聲明的函數(shù),開辟的函數(shù)開辟作用域,我們就2級作用域,以此類推像這樣的作用域
- 像一個鏈條一樣稱之為作用域鏈
塊作用域
1.一個 {}
就是一個塊級作用域,let 認塊級作用域
2.對于let而言,默認的全局也稱之為0級塊作用域,然后除了對象以外,大括號開辟新的塊作用域,0級上開辟的就是1級,1級里開辟的就是2級以此類推
3.跟我們之前學(xué)的函數(shù)作用域鏈是一樣的,只不過函數(shù)作用域只有函數(shù)開辟函數(shù)作用域,塊作用是大括號開辟塊作用域,var認函數(shù)作用域,let認塊級作用域
閉包
閉包就是一個函數(shù), 能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)
代碼示例:
function foo () { // foo的內(nèi)部變量 let num = 10 // 這個inner就叫閉包 function inner() { console.log(num) } }
閉包有什么用呢?
- 閉包相當(dāng)于是溝通外界和函數(shù)內(nèi)部的橋梁
- 也就是使用閉包就可以讓外界訪問到函數(shù)內(nèi)部的變量了
閉包和直接返回值有差別
直接返回值,其實本質(zhì)上只是返回這個值的數(shù)據(jù),后面的更改跟函數(shù)內(nèi)部的變量沒有任何關(guān)系
所以用閉包,就能讓外界間接的訪問到函數(shù)內(nèi)部的變量
閉包的幾種寫法
簡單來說:只要符合閉包特征的都算閉包
閉包:是一個函數(shù),一個能讓外界訪問函數(shù)內(nèi)部變量的函數(shù)
閉包作用1:延長變量生命周期
生命周期: 指從聲明到銷毀的周期
全局變量生命周期 從網(wǎng)頁打開到網(wǎng)頁結(jié)束
局部變量生命周期 從它所在的作用域開始到結(jié)束
正是因為閉包能延長變量的生命周期,所以外界依然能一直訪問局部變量
所以大量使用閉包,可能會導(dǎo)致內(nèi)存泄漏
內(nèi)存泄漏:一個數(shù)據(jù)后面已經(jīng)不需要用了,但是它還占著內(nèi)存空間,沒有被回收
解決辦法:
- 把閉包賦值為null即可
- 賦值為null,就代表這個數(shù)據(jù)沒有“人”引用了,沒人引用了那么就會被標(biāo)記為“垃圾”,然后會被GC在合適的時候回收
- GC:垃圾回收機制
- chrome瀏覽器用了這個機制
閉包作用2: 限制訪問
把變量變?yōu)榫植孔兞客饨缇蜔o法直接訪問
它只能通過我們寫的閉包(橋梁)來間接訪問,這樣做我們就可以對閉包里面做一些限制,這樣就起到了限制訪問的目的
閉包調(diào)用注意事項
注意:
產(chǎn)生閉包的外層函數(shù)調(diào)用多少次,就會產(chǎn)生多少個閉包,那么到時候操作的是不同的數(shù)據(jù),
如果產(chǎn)生閉包的外層函數(shù)調(diào)用1次,那么就只產(chǎn)生1個閉包,到時候操作的數(shù)據(jù)還是同一個
閉包解決用var導(dǎo)致下標(biāo)錯誤的問題
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> ul { list-style: none; padding: 0; margin: 0; } li { width: 30px; height: 30px; background-color: yellow; line-height: 30px; text-align: center; float: left; margin-right: 10px; } </style> </head> <body> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul> <script> // 以前有l(wèi)et嗎?沒有,所以我們看用var如何解決下標(biāo)問題 // 找到所有的li var lis = document.getElementsByTagName('li') for (var i = 0; i < lis.length; i++) { // 現(xiàn)在這里的i,只有1個變量,所以最終點擊的時候,大家訪問的都是一個i // 而i最終值是5,所以無論點誰都是5 // 解決辦法:我有5個li就要有5個變量,變量的值分別是0,1,2,3,4 // 如何才能產(chǎn)生5個不一樣的變量?就要開辟函數(shù)作用域 (function () { // 因為這個循環(huán)會產(chǎn)生5個自執(zhí)行函數(shù) // 就意味著有5個不同的index變量 // 然后它的值需要分別是0,1,2,3,4,而i的值剛好是0,1,2,3,4 // 所以把i賦值給index即可 var index = i // 給每個li加點擊事件 lis[i].onclick = function () { alert(index) } })() } </script> </body> </html>
投票機
// 要做一個能投票,能得到當(dāng)前票數(shù)的功能 function votor() { // 有一個變量,用來存票數(shù) let ticket = 0 return { getTicket: function () { console.log('當(dāng)前票數(shù)為:' + ticket) }, // 投票 add: function () { ticket++ } } } let tp = votor() tp.add() tp.add() tp.add() tp.add() tp.getTicket()
閉包兩個面試題
// 思考題 1: window.name = "The Window"; let object = { name: "My Object", getNameFunc: function () { return function () { return this.name; }; } }; console.log(object.getNameFunc()()); // 思考題 2: window.name = "The Window"; let object = { name: "My Object", getNameFunc: function () { let that = this; return function () { return that.name; }; } }; console.log(object.getNameFunc() ());
原型、原型鏈
原型對象
作用:
構(gòu)造函數(shù)中共有的屬性和方法添加到原型對象中,可以節(jié)省內(nèi)存
原型鏈
無論任何一個對象開始出發(fā), 按照 proto 開始向上查找, 最終都能找到 Object.prototype, 這個使用 __proto__
串聯(lián)起來的對象鏈狀結(jié)構(gòu), 叫做原型鏈
完整原型鏈圖
示意圖前置知識:
每一個對象都有__proto__
屬性, 指向所屬構(gòu)造函數(shù)的原型對象;
每一個對象都有prototype
屬性, 是一個對象;
函數(shù)也是對象;
當(dāng)一個對象, 沒有準確的構(gòu)造函數(shù)來實例化的時候, 我們都看作是內(nèi)置構(gòu)造函數(shù)
Object 的實例;Object的protype是頂級原型對象, 他的__protype__
指向是null
;
Function是頂級構(gòu)造函數(shù), 它自己是自己的構(gòu)造函數(shù), 同時自己是自己的實例對象(通俗來說, 就是它自己創(chuàng)建了自己)
完整原型示意圖:
以上就是JS難點同步異步的作用域與閉包原型及原型鏈詳解的詳細內(nèi)容,更多關(guān)于JS同步異步作用域與閉包原型及原型鏈的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript創(chuàng)建數(shù)組之聯(lián)合數(shù)組的使用方法示例
聯(lián)合數(shù)組也叫做鍵值數(shù)組,和php中的鍵值數(shù)組類似,下面看代碼如何演示2013-12-12parentElement,srcElement的使用小結(jié)
本篇文章主要是對parentElement,srcElement的使用進行了詳細的介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-01-01一篇文章帶你搞懂JavaScript的變量與數(shù)據(jù)類型
這篇文章主要為大家介紹了JavaScript的變量與數(shù)據(jù)類型,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-01-01