一次阿里面試後對函數本質的理解

一次阿里面試後對函數本質的理解

寫在前面

  • 環境:阿里的在線編程系統容許面試官在線考察面試者的編程能力.javascript

  • 考點:編程和理論.java

    • 編程:分爲技術自驅力、異步操做、編程風格(顆粒小)、變量做用域、DOM操做等.es6

    • 理論:性能優化,瀏覽器運行機制,協議/標準等web

本文側重於編程,在編程中對函數的運用是寫好程序的基礎。(參考開發者技能修煉的五個等級中「第二階梯:Developer,開發工程師」「知道了變量、邏輯與函數的意義」)面試

拋出一個問題

如何寫一個信號燈?(參考一道關於Promise應用的面試題)編程

那麼如何寫好一個信號燈?segmentfault

咱們首先發散一下思惟:promise,yield,async/await(ES7)。好的,技術點有了,那接下來該選擇哪一個方式呢?設計模式

不妨就選擇Promise,和其餘方式作個對比。數組

對比技術點

唉,一上來就看到async/await是ES7的特性,新生代的佼佼者,Promise已無用武之地?(參考Async/Await替代Promise的6個理由)promise

那咱們仍是先來看看有沒有挽回餘地(對promise多少有些感情了)?

  • 2.錯誤處理

文中錯誤處理一點說到「Async/Await讓try/catch能夠同時處理同步和異步錯誤。在下面的promise示例中,try/catch不能處理JSON.parse的錯誤,由於它在Promise中。咱們須要使用.catch,這樣錯誤處理代碼很是冗餘。而且,在咱們的實際生產代碼會更加複雜。」

咱們想一想問題根源應該是每步都須要catch,那將then中的函數統一放入數組,而後遞歸運行能夠解決這個問題。(另外,參考Toxicity:這些關鍵字有毒裏面有說到eval with try/catch對性能有必定的影響)

  • 3.條件語句

文中說到「須要獲取數據,而後根據返回數據決定是直接返回,仍是繼續獲取更多的數據。」

咱們能夠適當經過reject('')解決的,記得最後必定要有一個catch((err) => console.log(''))。等等那是和上面衝突了(每步catch)。這樣使用裝飾者模式對函數再wrapper。

  • 4.中間值

文中提到「你極可能遇到過這樣的場景,調用promise1,使用promise1返回的結果去調用promise2,而後使用二者的結果去調用promise3。」

咱們使用觀察者模式解決。

  • 6.調試

文中提到「最後一點,也是很是重要的一點在於,async/await可以使得代碼調試更簡單。2個理由使得調試Promise變得很是痛苦」

咱們也經過遞歸和 將要執行的函數放入一個數組解決。

對Promise幾個主要缺點找到了補償措施,就能夠進行編碼實現了。(固然咱們仍是要擁抱新特性的)

變量命名

export function singalLamp(singalArr) {
}

你們都知道對比typeScript,JS是動態+弱類型(動弱無關)。那麼變量命名就須要在表達清邏輯的同時攜帶變量類型。好的代碼是儘可能經過命名讓用戶理解和使用。(畢竟同時維護大量文檔和代碼是個難事)

總結一句就是:駝峯+邏輯+類型。

參數使用

var doSomething = function(obj) {
    var _adapter = {
        name : 'xioaming',
        titile : 'xiaoming',
        age : 24,
        color : 'pink',
        size : 100
    }

    for (var i in _adapter) {
        _adapter[i] = obj[i] || _adapter[i];
    }

    //dosomething
}
export function signalLight(data) {
  const sign = data.slice();
}
  • 對傳入的參數應該儘可能拆卸,以避免用戶傳參屬性變動。(屬性較多時,考慮使用適配器模式)

  • 變量的使用應盡力保證函數是純函數。對傳參deepClone/slice,不修改外部變量。

函數聲明

export function singalLamp(singalArr) {
    function tic(singal, time) {
        return () => new Promise((res) => setTimeout(() => {
            console.log(singal);
            res();
        }, time));
    }

    const rawArr = singalArr.slice();
}

函數的聲明/定義有A:function test() {} ; B:const test = function() {}; C:const test = () => {},那麼他們有神麼區別?

A方式:函數會提高,提高意味着在該做用域(scope)任何位置均可以使用。知道了這些,咱們能夠得出一個結論:使用該方式函數必須是純函數。

B/C方式:函數不會提高,此種方式通常定義一個非純函數,非純函數(這裏指依賴於外部的變量)提高了也沒有意義。由於它要依賴於上下文,即調用變量的初始化。

C方式:C方式中是一個箭頭函數,難免讓咱們思考爲何箭頭函數沒有function test() {}這種會提高的定義方式呢? 答案是箭頭函數自身的特性(this指向依賴詞法/靜態做用域),這使得箭頭函數的提高沒有意義。

函數使用

export function singalLamp(singalArr) {
    function tic(singal, time) {
        return () => new Promise((res) => setTimeout(() => {
            console.log(singal);
            res();
        }, time));
    }

    const rawArr = singalArr.slice();
    const lampArr = rawArr.reduce(function(prev, item) {
        return prev.concat([tic(item, 1000)]);
    }, []);
    const step = function(iterator) {
        if (iterator === lampArr.length) {
            return step(0);
        } else {
            return () => lampArr[iterator]().then(step(++iterator));
        }
    }

    step(0)();
}

singalLamp(['red', 'green', 'yellow']);

函數的使用主要有兩種:

  • 閉包

閉包的本質是(對共享變量的操做,典型運用是觀察者模式/備忘錄模式)

  • 普通

封裝,複用。(當我門對一段邏輯不須要複用時,咱們仍將它寫成函數的動機是:細顆粒化邏輯)

性能優化

在Web開發過程當中,能夠進行性能優化的方面多如牛毛,筆者在這裏介紹幾處切合本文主題的優化方式。即js的高性能代碼書寫(參考編寫高性能的JS代碼),這裏簡單說幾個:

  • i++與++i

使用前綴自增表達式,也能帶來小小的性能提高。(++i代替i++)

  • 閉包

雖然上文介紹了閉包的實用性,可是仍是應該儘可能避免使用閉包,它就和remove dom同樣讓人詬病。(垃圾回收問題,內存)

  • const與let

就 let 而言,他的使用場景應該是相對較少的,咱們只會在 loop(for,while 循環)及少許必須重定義的變量上用到他。

猜測:就執行效率而言,const 因爲不能夠從新賦值的特性,因此能夠作更多語法靜態分析方面的優化,從而有更高的執行效率。(參考阿里FED博客ES6 你可能不知道的事 - 基礎篇)

總結

要寫好一個項目須要兼容,性能,安全等。寫好一個功能須要設計模式和解耦需求。寫好一個函數須要考慮['對比技術點','變量命名','參數使用','函數聲明','函數使用'].join('+');

其餘

我的博客歡迎交流共勉成長

相關文章
相關標籤/搜索