本週總結請查收(內附21道前端面試題)

前言

本週發起了一個100天前端進階計劃,天天一個知識點,搞明白背後的原理,這是第一週的總結,請注意查收。前端

以面試題的形式看本身本週掌握了多少。git

目錄

  • 5道筆試題
  • 10道簡單題
  • 6道算法題

筆試題

1.下面代碼輸出什麼

// base.js
let count = 0;
setTimeout(() => {
    console.log("base.count", ++count);
}, 500)

module.exports.count = count;

// commonjs.js
const { count } = require('./base');
setTimeout(() => {
     console.log("count is" + count + 'in commonjs');
}, 1000)


// base1.js
let count = 0;
setTimeout(() => {
    console.log("base.count", ++count);
}, 500)
exports const count = count;

// es6.js
import { count } from './base1';
setTimeout(() => {
     console.log("count is" + count + 'in es6');
}, 1000)

答案:1,0,1,1

解析:

  1. CommonJs模塊輸出的是一個值的拷貝,也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值。
  2. ES6 模塊的運行機制與 CommonJS 不同。JS 引擎對腳本靜態分析的時候,遇到模塊加載命令import,就會生成一個只讀引用。等到腳本真正執行時,再根據這個只讀引用,到被加載的那個模塊裏面去取值。換句話說,ES6 的import有點像 Unix 系統的「符號鏈接」,原始值變了,import加載的值也會跟着變。所以,ES6 模塊是動態引用,而且不會緩存值,模塊裏面的變量綁定其所在的模塊。
詳細分析請看 《require和import的區別》

2.下面代碼輸出什麼

console.log((function() {
    console.log(1);
    setTimeout(function() {
        console.log(2)
    }, 1000)
    setTimeout(function() {
        console.log(3)
    }, 0);
    setTimeout(function() {
        console.log(4)
    }, 0);
    console.log(5)
})());

答案:1, 5, undefined, 3, 4, 2

詳細分析請看 《setTimeout和requestAnimationFrame》

3.下面代碼輸出什麼

console.log((typeof null ));
console.log((typeof []));

console.log((typeof Symbol()));
console.log((typeof 123n) );

function foo() {
    console.log(111);
};
console.log((typeof foo));

答案:

  • object
  • object
  • symbol
  • bigint
  • function

4.下面代碼輸出什麼

function *foo(x) {
    const y = 2 * (yield (x + 1));
    const z = yield (y / 3);
    return (x + y + z);
}

const  a = foo(5);
console.log(a.next());
console.log(a.next());
console.log(a.next());

const b = foo(5);
console.log(b.next());
console.log(b.next(12));
console.log(b.next(13));

答案:

{ value: 6, done: false }
{ value: NaN, done: false }
{ value: NaN, done: true }
{ value: 6, done: false }
{ value: 8, done: false }
{ value: 42, done: true }

解析:

先看使用Generator函數生成的迭代器a:es6

  1. 第一次調用next方法,遇到 yield 中止,返回yield表達式的值,此時爲 5 + 1 = 6;
  2. 第二次調用next方法,遇到 yield 中止,返回yield表達式的值,因爲next方法沒有帶參數,上一個yield表達式返回值爲undefined, 致使y的值等於2*undefined即(NaN),除以 3 之後仍是NaN,所以返回對象的value屬性也等於NaN
  3. 第三次調用next方法,執行的是 return (x + y + z),此時x的值爲 5y的值爲 NaN, 因爲next方法沒有帶參數,上一個yield表達式返回值爲undefined,致使z爲 undefined,返回對象的 value屬性等於5 + NaN + undefined,即 NaN

再來看看使用Generator函數生成的迭代器b:github

  1. 第一次調用next方法,遇到 yield 中止,返回yield表達式的值,此時爲 5 + 1 = 6;
  2. 第二次調用next方法,遇到 yield 中止,返回yield表達式的值,因爲next方法帶有參數12,因此上一個yield表達式返回值爲12, 所以y的值等於2*12即(24),除以 38,所以返回對象的value屬性爲8
  3. 第三次調用next方法,執行的是 return (x + y + z),此時x的值爲 5y的值爲 24, 因爲next方法沒有帶參數13,所以z爲13,返回對象的 value屬性等於5 + 24 + 13,即 42
詳細分析請看 Generator函數詳解》

5.下面代碼輸出什麼

let z = 1;
function *foo() {
    const x = yield 2;
    z++;
    const y = yield (x * z);
    console.log(x, y, z);
}
const a = foo();
const b = foo();

let val1 = a.next().value;
console.log(val1);

let val2 = b.next().value;
console.log(val2);

val1 = a.next(val2 * 10).value;
console.log(val1);

val2 = b.next(val1 * 5).value;
console.log(val2);

a.next(val2 / 2);

b.next(val1 / 4);

答案:

  • 2
  • 2
  • 40
  • 600
  • 20 300 3
  • 200 10 3

解析

  1. *foo()的兩個實例同時啓用,兩個next() 分別從yield 2 語句獲得2
  2. val2 * 10 也就是2 * 10,發送到第一個生成器實例 a, 由於x獲得的值20z1增長到2,而後 20 * 2經過 yield發出,將val1設置爲40
  3. val1 * 5 也就是 40 * 5,發送到第二個生成器實例 b,所以x獲得的值200z再從 2遞增到3,而後 200*3經過 yield 發出,將val2設置爲 600
  4. val2 / 2 也就是 600 / 2 發動到第一個生成器實例 a, 所以 y獲得值 300, 而後打印出 x y z 的值分別爲 20, 300, 3
  5. val1 / 4 也就是 40 / 4, 發送到第二個生成器實例 b, 所以 y獲得的值10, 而後打印出 x y z的值分別爲 200, 10, 3
詳細分析請看 《Generator函數》

簡答題

1. commonjs模塊和ES6模塊的區別

  • CommonJs模塊輸出的是一個值的拷貝,ES6模塊輸出的是值的引用。
  • CommonJs模塊是運行時加載,ES6模塊是編譯時輸出接口。
詳細分析請看 《require和import的區別》

2. JS有哪幾種數據類型

JavaScript有八種內置類型面試

  1. 空值(null)
  2. 未定義(undefined)
  3. 布爾值(boolean)
  4. 數字(number)
  5. 字符串(string)
  6. 對象 (object)
  7. 符號(symbol, ES6中新增)
  8. 大整數(BigInt, ES2020 引入)

除對象外,其餘統稱爲「基本類型」。算法

注意新增的 symbolBigInt

3. typeof 原理是什麼

typeof原理: 不一樣的對象在底層都表示爲二進制,在Javascript中二進制前(低)三位存儲其類型信息數組

  • 000: 對象
  • 010: 浮點數
  • 100:字符串
  • 110: 布爾
  • 1: 整數

typeof null 爲"object", 緣由是由於 不一樣的對象在底層都表示爲二進制,在Javascript中二進制前(低)三位都爲0的話會被判斷爲Object類型,null的二進制表示全爲0,天然前三位也是0,因此執行typeof時會返回"object"。瀏覽器

關鍵詞:JavaScript數據類型的相關底層機制

4. instanceof 原理是什麼,本身能夠自定義一個麼

instanceof的語法:緩存

object instanceof constructor
// 等同於
constructor.prototype.isPrototypeOf(object)
  • object: 要檢測的對象
  • constructor:某個構造函數

instanceof原理: 檢測 constructor.prototype是否存在於參數 object的 原型鏈上。instanceof 查找的過程當中會遍歷object 的原型鏈,直到找到 constructorprototype ,若是查找失敗,則會返回false,告訴咱們,object 並不是是 constructor 的實例。微信

對象的Symbol.hasInstance屬性,指向一個內部方法。當其餘對象使用instanceof運算符,判斷是否爲該對象的實例時,會調用這個方法。好比,foo instanceof Foo在語言內部,實際調用的是FooSymbol.hasInstance

class MyClass {
  [Symbol.hasInstance](foo) {
    return foo instanceof Array;
  }
}
[1, 2, 3] instanceof new MyClass() // true
關鍵詞:instanceof 用法,原型鏈, Symbol.hasInstance。詳細分析請查看 《 typeof和instanceof原理》

5. setTimeout和setInterval 區別是什麼,怎麼用 setTimeout實現 setInterval

  • setTimeout: 指定延期後調用函數,每次setTimeout計時到後就會去執行,而後執行一段時間後才繼續setTimeout,中間就多了偏差,(偏差多少與代碼的執行時間有關)。
  • setInterval:以指定週期調用函數,而setInterval則是每次都精確的隔一段時間推入一個事件(可是,事件的執行時間不必定就不許確,還有多是這個事件還沒執行完畢,下一個事件就來了).
setTimeout(function fn(){
    console.log('我被調用了');
    setTimeout(fn, 100);
},100);
詳細分析請看 《setTimeout和requestAnimationFrame》

6. 怎麼理解 setTimeout(()=> {}, 0)

執行該語句時,是當即把當前定時器代碼推入事件隊列,當定時器在事件列表中知足設置的時間值時將傳入的函數加入任務隊列,以後的執行就交給任務隊列負責。可是若是此時任務隊列不爲空,則需等待,因此執行定時器內代碼的時間可能會大於設置的時間。

HTML5標準規定了setTimeout()的第二個參數的最小值(最短間隔)不得低於4毫秒。 當指定的時間低於該時間時,瀏覽器會用最小容許的時間做爲setTimeout的時間間隔,也就是說即便咱們把setTimeout的延遲時間設置爲0,實際上可能爲 4毫秒後才事件推入任務隊列。

詳細分析請看 《setTimeout和requestAnimationFrame》

7. requestAnimationFrame是什麼,有什麼應用場景, requestIdleCallback是什麼,有什麼應用場景

  • requestAnimationFrame是瀏覽器用於定時循環操做的一個接口,相似於setTimeout,主要用途是按幀對網頁進行重繪。
  • requestIdleCallback()經常使用來切割長任務,利用空閒時間執行,避免主線程長時間阻塞。
詳細分析請看 《setTimeout和requestAnimationFrame》

8. for...of 原理是什麼?

for...of 不僅是用來遍歷數組的,只要有iterator 接口的數據結構均可以用它來遍歷。一個數據結構只要部署了Symbol.iterator屬性,就被視爲具備 iterator 接口。iterator的實現思想來源於 單向鏈表

關鍵詞: iterator, Symbol.iterator, 單向鏈表。詳細分析請看 《for...of原理解析》

9. 本身實現一個迭代器?

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        { 
            value: array[nextIndex++],
            done: false
        } 
        :
        {
            value: undefined,
            done: true
        };
    }
  };
}
const it = makeIterator(['a', 'b']);

it.next() 
// { value: "a", done: false }
it.next() 
// { value: "b", done: false }
it.next() 
// { value: undefined, done: true }

10. Gennrator哪些特性決定它能夠解決異步?

  • 能夠暫停執行(yield)恢復執行(next)
  • 函數體內外的數據交換(next返回值的value,是向外輸出數據,next方法的參數,是向內輸入數據)和錯誤處理機制(Generator 函數內部還能夠部署錯誤處理代碼,捕獲函數體外拋出的錯誤)
更多請查看 Generator函數詳解》

算法題

1. 買賣股票的最佳時機I

給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。

若是你最多隻容許完成一筆交易(即買入和賣出一支股票),設計一個算法來計算你所能獲取的最大利潤。

注意你不能在買入股票前賣出股票。

示例 1:

輸入: [7,1,5,3,6,4]
輸出: 5
解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 5 天(股票價格 = 6)的時候賣出,最大利潤 = 6-1 = 5 。
     注意利潤不能是 7-1 = 6, 由於賣出價格須要大於買入價格。

示例 2:

輸入: [7,6,4,3,1]
輸出: 0
解釋: 在這種狀況下, 沒有交易完成, 因此最大利潤爲 0。

答案: 買賣股票的最佳時機

2. 買賣股票的最佳時機II

給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。

設計一個算法來計算你所能獲取的最大利潤。你能夠儘量地完成更多的交易(屢次買賣一支股票)。

注意:你不能同時參與多筆交易(你必須在再次購買前出售掉以前的股票)。

示例 1:

輸入: [7,1,5,3,6,4]
輸出: 7
解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 3 天(股票價格 = 5)的時候賣出, 這筆交易所能得到利潤 = 5-1 = 4 。
     隨後,在第 4 天(股票價格 = 3)的時候買入,在第 5 天(股票價格 = 6)的時候賣出, 這筆交易所能得到利潤 = 6-3 = 3 。

示例 2:

輸入: [1,2,3,4,5]
輸出: 4
解釋: 在第 1 天(股票價格 = 1)的時候買入,在第 5 天 (股票價格 = 5)的時候賣出, 這筆交易所能得到利潤 = 5-1 = 4 。
     注意你不能在第 1 天和第 2 天接連購買股票,以後再將它們賣出。
     由於這樣屬於同時參與了多筆交易,你必須在再次購買前出售掉以前的股票。

示例 3:

輸入: [7,6,4,3,1]
輸出: 0
解釋: 在這種狀況下, 沒有交易完成, 因此最大利潤爲 0。

答案: 《買賣股票的最佳時機》

3. 合併兩個有序鏈表

將兩個有序鏈表合併爲一個新的有序鏈表並返回。新鏈表是經過拼接給定的兩個鏈表的全部節點組成的。
示例:

輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4

答案:合併兩個有序鏈表

4. 最大子序和

給定一個整數數組 nums ,找到一個具備最大和的連續子數組(子數組最少包含一個元素),返回其最大和。
示例:

輸入: [-2,1,-3,4,-1,2,1,-5,4],
輸出: 6
解釋: 連續子數組 [4,-1,2,1] 的和最大,爲 6。

答案:最大子序和

5.撲克牌中的順子

從撲克牌中隨機抽5張牌,判斷是否是一個順子,即這5張牌是否是連續的。2~10爲數字自己,A爲1,J爲11,Q爲12,K爲13,而大、小王爲 0 ,能夠當作任意數字。A 不能視爲 14。

示例 1:
輸入: [1,2,3,4,5]
輸出: True
 

示例 2:
輸入: [0,0,1,2,5]
輸出: True

限制:
1.數組長度爲 5 
2.數組的數取值爲 [0, 13] .

答案:撲克牌中的順子

6.無重複字符的最長子串

給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。

示例 1:

輸入: "abcabcbb"
輸出: 3 
解釋: 由於無重複字符的最長子串是 "abc",因此其長度爲 3。

示例 2:

輸入: "bbbbb"
輸出: 1
解釋: 由於無重複字符的最長子串是 "b",因此其長度爲 1。

示例 3:

輸入: "pwwkew"
輸出: 3
解釋: 由於無重複字符的最長子串是 "wke",因此其長度爲 3。請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。

答案:無重複字符的最長子串

碎碎念

最新發起了一個100天前端進階計劃,致力於弄明白每一個知識點背後的原理。這是第一週的總結,原本想直接粘貼一下原先的標題並附上原文連接。後來想仍是找幾道關於本週內容的一些面試題(大部分爲原文中的例子),方便檢測一下本身的掌握程度。一共20道,看看本身能得幾分。算法題作多要在半個小時以內寫出最優解,上面提供的答案並必定是最好的,若是有問題或者更好的解法歡迎你們留言指出。或者你最新碰到的相似的面試題,也能夠提供給我進行補充。

其餘

最近發起了一個100天前端進階計劃,主要是深挖每一個知識點背後的原理,歡迎關注 微信公衆號「牧碼的星星」,咱們一塊兒學習,打卡100天。

牧碼的星星

相關文章
相關標籤/搜索