js是單線程的,內部要處理的任務分同步任務、異步任務。
異步任務分微任務、宏任務
執行順序:【又稱 事件循環機制 】
先執行同步任務,遇到異步宏任務則將異步宏任務放入宏任務隊列中,遇到異步微任務則將異步微任務放入微任務隊列中。當所有同步任務執行完畢后,再將異步微任務從隊列中調入主線程執行,微任務執行完畢后再將異步宏任務從隊列中調入主線程執行,一直循環直至所有任務執行完畢。
微任務和宏任務有哪些:
示例:
setTimeout(function(){ console.log(1); }); new Promise(function(resolve){ console.log(2); resolve(); }).then(function(){ console.log(3); }).then(function(){ console.log(4) }); console.log(5); // 2 5 3 4 1
遇到setTimout,異步宏任務,放入宏任務隊列中。
遇到new Promise,new Promise在實例化的過程中所執行的代碼都是同步進行的,所以輸出2。
Promise.then,異步微任務,將其放入微任務隊列中。
遇到同步任務console.log(5);輸出5;主線程中同步任務執行完。
從微任務隊列中取出任務到主線程中,輸出3、 4,微任務隊列為空。
從宏任務隊列中取出任務到主線程中,輸出1,宏任務隊列為空。
相同點:
不同點:
注意:
async和defer屬性都僅適用于外部腳本,如果script標簽沒有src屬性,盡管寫了async、defer屬性也會被忽略。
深拷貝和淺拷貝是只針對Object和Array這樣的引用數據類型的。
js中基本數據類型存放在棧中,引用數據類型存放在堆中。
淺拷貝是在堆中先創建一個新對象,拷貝原始對象的屬性值。如果屬性是基本類型,拷貝的就是基本類型的值,如果屬性是引用類型,拷貝的就是內存地址。
深拷貝是在堆中先創建一個新對象,采用遞歸方法實現深度克隆原理,將一個對象從內存中完整的拷貝一份出來。如果屬性是基本類型,拷貝的就是基本類型的值,如果屬性是引用類型,在堆中創建一個新對象再完整拷貝原對象。
區別:
實現:
雙重for循環 + splice。
for(var i=0;i<arr.length;i++){ for(var j=i+1;j<arr.length;j++){ if(arr[i]===arr[j]){ arr.splice(j,1) j-- } }}
filter + indexOf,返回item第一次出現的位置等于當前的index的元素 【常用】。
let newArr = arr.filter((item, index) => arr.indexOf(item) === index);
filter + Object.hasOwnProperty,利用對象的鍵名不可重復的特點
let obj = {}arr.filter(item => obj.hasOwnProperty(typeof item + item) ? false : obj[typeof item])
new Set + 擴展運算符 或 Array.from 【常用】。
let newArr = [...new Set(arr)];let newArr = Array.from(new Set(arr));
ObjA.call(ObjB, argument) --- ObjB調用ObjA中的方法,并把argument作為參數傳入。
作用:改變this的指向。
區別:
調用方式不同:
參數不同:
三者第一個參數都是調用的對象。
原型:
每個構造函數都有一個prototype屬性,即 顯式原型屬性,它指向構造函數的原型對象。
每個實例對象都有一個__proto__屬性,即 隱式原型屬性,它指向構造函數的原型對象。
通過顯式原型屬性向原型對象上設置值,通過隱式原型屬性向原型對象上讀取值,即 實例對象的隱式原型屬性值等于其構造函數的顯式原型屬性值。
原型鏈:
每個構造函數的原型對象,默認是一個空的Object構造函數的實例對象,也都有一個__proto__屬性。
實例對象和原型對象的__proto__屬性連接起來的一條鏈,即 原型鏈,它的盡頭是Object構造函數的原型對象的__proto__屬性。
當在實例對象上讀取值時,先在實例對象本身上找,當找不到,再通過__proto__屬性,在其構造函數的原型對象上找,
如果還找不到,就繼續沿著__proto__屬性向上找,直到Object構造函數的原型對象的__proto__屬性為止,此時值為null。
定義在一個函數體內,且訪問了外部函數變量 的函數,即 閉包函數(閉包)。
優點:
缺點:會導致內存泄露,所以要謹慎使用。
應用場景:
回調和閉包的區別:【是否定義在函數體內】。
例:
function handle(msg, time) { setInterval(function callback() { console.log(msg); }, time)}handle("哈哈哈哈", 5000)
對于setInterval函數來說,callback函數是回調函數。
對于handle函數來說,callback函數是閉包函數。
普通函數:普通函數中this是動態的,在調用函數時確定,一般誰調用指向誰。
調用方式 this指向。
普通函數調用 window。
構造函數調用 實例對象。
對象方法調用 該方法所屬對象。
事件綁定方法 綁定事件的對象。
定時器函數 window。
立即執行函數 window。
箭頭函數:
箭頭函數沒有自己的this、arguments。
箭頭函數的this是靜態的,在定義函數時確定,一般和箭頭函數所在父作用域的this指向一致。
作用:
都是可以限制函數的執行頻次,避免函數觸發頻率過高導致響應速度跟不上觸發頻率,因而出現延遲、假死或卡頓的現象。
都使用定時器實現。
防抖(debounce):【多次重新計時】。
在事件被觸發n秒后再執行回調,如果在這n秒內又被觸發,則重新計時。
典型的案例:輸入框搜索,輸入結束后n秒才進行搜索請求,n秒內又輸入內容,則重新計時。
節流(throttle):【多次只一次生效】。
規定在一個單位時間內,只能觸發一次函數,如果這個單位時間內觸發多次函數,只有一次生效。
典型的案例:鼠標不斷點擊按鈕觸發事件,規定在n秒內多次點擊只生效一次。
原因:const指針指向的地址是不可以改變的,但地址指向的內容是可以改變的。
Promise對象:
描述:
三種狀態:
九種方法:
對象上有resolve、reject、all、allSettled、race、any方法:
原型上有then、catch、finally方法:
async與await:
出現目的:
async:
await:
必須放在async定義的函數內部去使用。
作用:
異步變同步的解決,經歷了四個階段:
描述:
回調里面嵌入回調,導致層次很深,代碼維護起來特別復雜,產生回調地獄問題。
示例代碼:
getData(){ //獲取分類列表id uni.request({ url:"https://ku.qingnian8.com/dataApi/news/navlist.php", success:res=>{ let id=res.data[0].id // 根據分類id獲取該分類下的所有文章 uni.request({ url:"https://ku.qingnian8.com/dataApi/news/newslist.php", data:{ cid:id }, success:res2=>{ //獲取到一篇文章的id,根據文章id找到該文章下的評論 let id=res2.data[0].id; uni.request({ url:"https://ku.qingnian8.com/dataApi/news/comment.php", data:{ aid:id }, success:res3=>{ //找到該文章下所有的評論 console.log(res3) } }) } }) } })}
描述:
示例代碼:
//在onload初始化后調用相應的函數onLoad() { //調用導航函數,并拿到函數的返回值 this.getNav(res=>{ let id=res.data[0].id; //拿到分類id作為參數 this.getArticle(id,res2=>{ //拿到文章id作為參數 let id=res2.data[0].id; this.getComment(id,res3=>{ //最終獲取到第一個分類下,第一篇文章下,所有評論 console.log(res3) }) }) });}methods: { //先獲取導航分類接口,將結果進行返回,到調用函數的地方獲取 getNav(callback){ uni.request({ url:"https://ku.qingnian8.com/dataApi/news/navlist.php", success:res=>{ callback(res) } }) }, //獲取文章數據,將文章列表進行返回 getArticle(id,callback){ uni.request({ url:"https://ku.qingnian8.com/dataApi/news/newslist.php", data:{ cid:id }, success:res=>{ callback(res) } }) }, //獲取文章下的所有評論 getComment(id,callback){ uni.request({ url:"https://ku.qingnian8.com/dataApi/news/comment.php", data:{ aid:id }, success:res=>{ callback(res) } }) }}
示例代碼:
//promise鏈式調用this.getNav().then(res=>{let id=res.data[0].id;return this.getArticle(id);}).then(res=>{let id=res.data[0].id;return this.getComment(id)}).then(res=>{console.log(res)}) methods: { //先獲取導航分類接口,將結果進行返回,到調用函數的地方獲取 getNav(callback){ return new Promise((resolve,reject)=>{ uni.request({ url:"https://ku.qingnian8.com/dataApi/news/navlist.php", success:res=>{ resolve(res) }, fail:err=>{ reject(err) } }) }) }, //獲取文章數據,將文章列表進行返回 getArticle(id){ return new Promise((resolve,reject)=>{ uni.request({ url:"https://ku.qingnian8.com/dataApi/news/newslist.php", data:{ cid:id }, success:res=>{ resolve(res) }, fail:err=>{ reject(err) } }) }) }, //獲取文章下的所有評論 getComment(id){ return new Promise((resolve,reject)=>{ uni.request({ url:"https://ku.qingnian8.com/dataApi/news/comment.php", data:{ aid:id }, success:res=>{ resolve(res) }, fail:err=>{ reject(err) } }) }) } }
描述:
await / async 這兩個命令是成對出現的,如果使用await沒有在函數中使用async命令,那就會報錯,如果直接使用async沒有使用await不會報錯,只是返回的函數是個promise
示例代碼:
async onLoad() { let id,res; res=await this.getNav(); id=res.data[0].id; res=await this.getArticle(id); id=res.data[0].id; res=await this.getComment(id); console.log(res)} methods: { //先獲取導航分類接口,將結果進行返回,到調用函數的地方獲取 getNav(callback){ return new Promise((resolve,reject)=>{ uni.request({ url:"https://ku.qingnian8.com/dataApi/news/navlist.php", success:res=>{ resolve(res) }, fail:err=>{ reject(err) } }) }) }, //獲取文章數據,將文章列表進行返回 getArticle(id){ return new Promise((resolve,reject)=>{ uni.request({ url:"https://ku.qingnian8.com/dataApi/news/newslist.php", data:{ cid:id }, success:res=>{ resolve(res) }, fail:err=>{ reject(err) } }) }) }, //獲取文章下的所有評論 getComment(id){ return new Promise((resolve,reject)=>{ uni.request({ url:"https://ku.qingnian8.com/dataApi/news/comment.php", data:{ aid:id }, success:res=>{ resolve(res) }, fail:err=>{ reject(err) } }) }) } }
示例代碼:
// 1const xhr = new XMLHttpRequest();// 2xhr.open('POST', "http://localhost:xxx");// 3xhr.send("a=100&b=200");// 4xhr.onreadystatechange = function(){ if(xhr.readyState==4){ // 5 if(xhr.status >= 200 && xhr.status < 300){ result.innerHTML = xhr.response; } }}
作用:
一個模塊就是實現某個特定功能的文件,在文件中定義的變量、函數、類都是私有的,對其他文件不可見。
為了解決引入多個js文件時,出現 命名沖突、污染作用域 等問題。
AMD:
瀏覽器端模塊解決方案。
AMD即是“異步模塊定義”。
在AMD規范中,我們使用define定義模塊,使用require加載模塊。
提前執行:它采用異步方式加載模塊,一邊加載一邊執行。
依賴前置:依賴必須在定義時引入。
CMD:
瀏覽器端模塊解決方案。
CMD即是“通用模塊定義”。
在CMD規范中,我們使用define定義模塊,使用require加載模塊。
延遲執行:它采用異步方式加載模塊,先加載完畢再按需執行。
依賴就近:依賴可以在代碼的任意一行引入。
CommonJS:
服務器端模塊解決方案。
在CommonJS規范中,我們使用module.exports導出模塊,使用require加載模塊。
立即執行:它采用同步方式加載模塊,先加載后執行,執行完畢會被緩存。
依賴就近:依賴可以在代碼的任意一行引入。
ESModule:
瀏覽器端 和 服務器端 通用的模塊解決方案。
在ESModule規范中,我們使用export導出模塊,使用import加載模塊。
延遲執行:它采用異步方式加載模塊,先加載完畢再按需執行。
依賴就近:依賴可以在代碼的任意一行引入。
查:
增:
刪:
改:
屬性操作:
內容操作:
對象字面量(花括號)。
工廠模式(對象字面量 + return新對象)。
Object構造函數(new Object)。
構造函數模式(new function + 屬性、方法都在構造函數上)。
原型模式(new function + 屬性、方法都在原型上)。
組合模式(屬性在構造函數上 + 方法在原型上)。
類(底層就是對 組合模式 進行了封裝)。
原型鏈繼承(子類原型指向父類實例)。
構造函數繼承(借助 call)。
組合繼承(原型鏈繼承 + 構造函數繼承)。
原型式繼承(借助 Object.create)。
寄生式繼承(原型式繼承 + 添加子類方法)。
寄生組合繼承(寄生式繼承 + 組合繼承)
extends(底層就是對 寄生組合繼承 進行了封裝)
在 代碼執行前 產生。
產生變量提升、函數提升的原因。
定義:
執行上下文棧:
存放執行上下文對象的棧。
按照上下文對象創建的次序進棧,然后從棧頂依次執行出棧。
二十八、說一下什么是作用域、作用域鏈?
在代碼編寫時產生。
定義:
作用域鏈:
在某一作用域內找某一變量時,先在自身作用域內的執行上下文對象中找,找不到再去父作用域內的執行上下文對象中找,依次向上找,直到全局作用域內的執行上下文對象為止。這個過程稱為作用域鏈。
本文鏈接:http://www.www897cc.com/showinfo-26-22491-0.htmlJS面試題:公司真實JS面試題整理
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 基于熵的不確定性預測
下一篇: C 語言函數宏封裝妙招