前端面試題 -- JavaScript(二)

前言

上一篇 前端面試題-JavaScript(一), 感興趣的小夥伴也能夠移步這裏查看 完整版JavaScript面試題,面試題會不按期更新加進去一些我的工做中遇到的或者認爲比較重要的東西,後面會涉及到前端的各個方面,感興趣的小夥伴能夠關注哦!javascript

若是文章中有出現紕漏、錯誤之處,還請看到的小夥伴留言指正,先行謝過html

如下 ↓前端

1. 同步和異步的區別,怎麼異步加載 JavaScript

同步模式

同步模式,又稱阻塞模式。javascript 在默認狀況下是會阻塞加載的。當前面的 javascript 請求沒有處理和執行完時,會阻止瀏覽器的後續處理java

異步模式

異步加載又叫非阻塞,瀏覽器在下載執行 js 同時,還會繼續進行後續頁面的處理nginx

異步加載 JavaScript
  • 動態添加 script 標籤
  • defer
  • async
defer屬性和 async都是屬於 script 標籤上面的屬性,二者都能實現 JavaScript 的異步加載。不一樣之處在於: async 在異步加載完成的時候就立刻開始執行了, defer 會等到 html 加載完畢以後再執行

2. 跨域問題的產生,怎麼解決它

因爲瀏覽器的 同源策略,在出現 域名、端口、協議有一種不一致時,就會出現跨域,屬於瀏覽器的一種安全限制。

解決跨域問題有不少種方式,經常使用的就是如下幾種:git

  • jsonp 跨域:動態建立script,再請求一個帶參網址實現跨域通訊.缺點就是隻能實現 get 一種請求
  • document.domain + iframe跨域:兩個頁面都經過js強制設置document.domain爲基礎主域,就實現了同域.可是僅限主域相同,子域不一樣的跨域應用場景
  • 跨域資源共享(CORS):只服務端設置Access-Control-Allow-Origin便可,前端無須設置,若要帶cookie請求:先後端都須要設置
  • nginx反向代理接口跨域:同源策略是瀏覽器的安全策略,不是HTTP協議的一部分。服務器端調用HTTP接口只是使用HTTP協議,不會執行JS腳本,不須要同源策略,也就不存在跨越問題
  • WebSocket協議跨域

3. 對 this 的理解

JavaScript 中,研究 this 通常都是 this 的指向問題,核心就是 this 永遠指向最終調用它的那個對象,除非改變 this 指向或者箭頭函數那種特殊狀況es6

function test() {
    console.log(this);
}

test() // window

var obj = {
  foo: function () { console.log(this.bar) },
  bar: 1
};

var foo = obj.foo;
var bar = 2;

obj.foo() // 1
foo() // 2

// 函數調用的環境不一樣,所獲得的結果也是不同的

4. apply()、call()和 bind() 是作什麼的,它們有什麼區別

相同點:三者均可以改變 this 的指向github

不一樣點:web

  • apply 方法傳入兩個參數:一個是做爲函數上下文的對象,另一個是做爲函數參數所組成的數組
var obj = {
    name : 'sss'
}

function func(firstName, lastName){
    console.log(firstName + ' ' + this.name + ' ' + lastName);
}

func.apply(obj, ['A', 'B']);    // A sss B
  • call 方法第一個參數也是做爲函數上下文的對象,可是後面傳入的是一個參數列表,而不是單個數組
var obj = {
    name: 'sss'
}

function func(firstName, lastName) {
    console.log(firstName + ' ' + this.name + ' ' + lastName);
}

func.call(obj, 'C', 'D');       // C sss D
  • bind 接受的參數有兩部分,第一個參數是是做爲函數上下文的對象,第二部分參數是個列表,能夠接受多個參數
var obj = {
    name: 'sss'
}

function func() {
    console.log(this.name);
}

var func1 = func.bind(null, 'xixi');
func1();
applycall 方法都會使函數當即執行,所以它們也能夠用來調用函數

bind 方法不會當即執行,而是返回一個改變了上下文 this 後的函數。而原函數 func 中的 this 並無被改變,依舊指向全局對象 window面試

bind 在傳遞參數的時候會將本身帶過去的參數排在原函數參數以前

function func(a, b, c) {
    console.log(a, b, c);
}
var func1 = func.bind(this, 'xixi');
func1(1,2) // xixi 1 2

5. 什麼是內存泄漏,哪些操做會形成內存泄漏

內存泄漏:是指一塊被分配的內存既不能使用,又不能回收,直到瀏覽器進程結束

可能形成內存泄漏的操做:

  • 意外的全局變量
  • 閉包
  • 循環引用
  • 被遺忘的定時器或者回調函數

你可能還須要知道 垃圾回收機制 此外,高程上面對垃圾回收機制的介紹也很全面,有興趣的小夥伴能夠看看

6. 什麼是事件代理,它的原理是什麼

事件代理:通俗來講就是將元素的事件委託給它的父級或者更外級元素處理

原理:利用事件冒泡機制實現的

優勢:只須要將同類元素的事件委託給父級或者更外級的元素,不須要給全部元素都綁定事件,減小內存空間佔用,提高性能; 動態新增的元素無需從新綁定事件

7. 對AMD和CMD的理解,它們有什麼區別

AMDCMD都是爲了解決瀏覽器端模塊化問題而產生的, AMD規範對應的庫函數有 Require.jsCMD規範是在國內發展起來的,對應的庫函數有 Sea.js

AMD和CMD最大的區別是對依賴模塊的執行時機處理不一樣

一、AMD推崇依賴前置,在定義模塊的時候就要聲明其依賴的模塊

二、CMD推崇就近依賴,只有在用到某個模塊的時候再去require

參考:AMD-中文版 CMD-規範

8. 對ES6的瞭解

ECMAScript 6.0 是 JavaScript 語言的下一代標準

新增的特性:

  • 聲明變量的方式 let const
  • 變量解構賦值
  • 字符串新增方法 includes() startsWith() endsWith()
  • 數組新增方法 Array.from() Array.of() entries() keys() values()
  • 對象簡潔寫法以及新增方法 Object.is() Object.assign() entries() keys() values()
  • 箭頭函數、rest 參數、函數參數默認值等
  • 新的數據結構: SetMap
  • Proxy
  • Promise對象
  • async函數 await命令
  • Class
  • Module 體系 模塊的加載和輸出方式

瞭解更多,參考 ES6入門-阮一峯

9. 箭頭函數有什麼特色

ES6 容許使用「箭頭」(=>)定義函數
var f = v => v;

// 等同於
var f = function (v) {
  return v;
}

注意點:

  • 函數體內的 this 對象,就是定義時所在的對象,而不是使用時所在的對象
  • 不能夠看成構造函數,也就是說,不可使用 new 命令,不然會拋出一個錯誤
  • 不可使用 arguments 對象,該對象在函數體內不存在。若是要用,能夠用 rest 參數代替

10. Promise 對象的瞭解

Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大.所謂Promise,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果 --ES6入門-阮一峯

Promise 對象表明一個異步操做,有三種狀態:pending(進行中)、fulfilled(已成功)和 rejected(已失敗)。只有異步操做的結果,能夠決定當前是哪種狀態,任何其餘操做都沒法改變這個狀態

特色:

  • 對象的狀態不受外界影響
  • 一旦狀態改變,就不會再變,任什麼時候候均可以獲得這個結果
  • Promise 新建後就會當即執行
const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操做成功 */){
    resolve(value);
  } else {
    reject(error);
  }
})
Promise實例生成之後,能夠用then方法分別指定resolved狀態和rejected狀態的回調函數
promise.then(function(value) {
  // success
}, function(error) {
  // failure
})
then 方法返回的是一個新的Promise實例

Promise.prototype.catch 用於指定發生錯誤時的回調函數,具備「冒泡」性質,會一直向後傳遞,直到被捕獲爲止。也就是說,錯誤老是會被下一個catch語句捕獲

getJSON('/post/1.json').then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // 處理前面三個Promise產生的錯誤
});
catch 方法返回的仍是一個 Promise 對象,所以後面還能夠接着調用 then 方法

出去上述方法,Promise還有其餘用法,小夥伴們能夠在這裏查看大佬寫的文章 ES6入門-阮一峯

11. async 函數以及 awit 命令

async 函數是什麼?一句話,它就是 Generator 函數的語法糖

瞭解Generator函數的小夥伴,這裏 傳送門

async 特色:

async 函數返回一個 Promise 對象,可使用 then 方法添加回調函數。當函數執行的時候,一旦遇到 await 就會先返回,等到異步操做完成,再接着執行函數體內後面的語句

async 函數內部 return 語句返回的值,會成爲 then 方法回調函數的參數

async 函數返回的 Promise 對象,必須等到內部全部 await 命令後面的 Promise 對象執行完,纔會發生狀態改變,除非遇到 return 語句或者拋出錯誤

async 函數內部拋出錯誤,會致使返回的 Promise 對象變爲 reject 狀態。拋出的錯誤對象會被 catch 方法回調函數接收到

function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 50);
await 命令: await 命令後面是一個 Promise 對象,返回該對象的結果。若是不是 Promise 對象,就直接返回對應的值
async function f() {
  // 等同於
  // return 123;
  return await 123;
}

f().then(v => console.log(v))
// 123
await 命令後面是一個 thenable對象(即定義then方法的對象),那麼 await會將其等同於 Promise 對象.也就是說就算一個對象不是 Promise對象,可是隻要它有 then這個方法, await 也會將它等同於 Promise對象

使用注意點:

  • await 命令後面的 Promise 對象,運行結果多是 rejected,因此最好把 await 命令放在 try...catch 代碼塊中
  • 多個 await 命令後面的異步操做,若是不存在繼發關係,最好讓它們同時觸發
  • await 命令只能用在 async 函數之中,若是用在普通函數,就會報錯

瞭解更多,請點擊 這裏

12. export 與 export default有什麼區別

exportexport default 都可用於導出常量、函數、文件、模塊等

在一個文件或模塊中,exportimport 能夠有多個,export default 僅有一個

經過 export 方式導出,在導入時要加 { }export default 則不須要

使用 export default命令,爲模塊指定默認輸出,這樣就不須要知道所要加載模塊的變量名; export 加載的時候須要知道加載模塊的變量名

export default 命令的本質是將後面的值,賦給 default 變量,因此能夠直接將一個值寫在 export default 以後

13. 前端性能優化

參見 雅虎14條前端性能優化

14. 對JS引擎執行機制的理解

首選明確兩點:

JavaScript 是單線程語言

JavaScriptEvent LoopJS 的執行機制, 也就是事件循環

console.log(1)
    
setTimeout(function(){
    console.log(2)
},0)

console.log(3)

// 1 3 2
JavaScript 將任務分爲同步任務和異步任務,執行機制就是先執行同步任務,將同步任務加入到主線程,遇到異步任務就先加入到 event table ,當全部的同步任務執行完畢,若是有可執行的異步任務,再將其加入到主線程中執行

視頻詳解,移步 這裏

setTimeout(function(){console.log(1);},0);
new Promise(function(resolve){
     console.log(2);
     for(var i = 0; i < 10000; i++){
         i == 99 && resolve();
     }
 }).then(function(){
     console.log(3)
 });
 
 console.log(4);
 
 // 2 4 3 1

在異步任務中,定時器也屬於特殊的存在。有人將其稱之爲 宏任務、微任務,定時器就屬於宏任務的範疇。

參考 JS引擎的執行機制

後記

總結的過程,本身確實也獲益頗多,感謝前行的小夥伴。

GitHub完整版面試題,歡迎小夥伴們star關注

預祝你們都能找到本身滿意的工做

以上

相關文章
相關標籤/搜索