1. 程式人生 > >JavaScript 函數式編程讀書筆記2

JavaScript 函數式編程讀書筆記2

共享 基於 容器 避免 api mutable 詳解 zen api state

概述

這是我讀《javascript函數式編程》的讀書筆記,供以後開發時參考,相信對其他人也有用。

說明:雖然本書是基於underscore.js庫寫的,但是其中的理念和思考方式都講的很好,值得一讀。不過如果不熟悉underscore.js庫的話,讀起來會有點困難。

《javascript函數式編程》讀書筆記1

對象的不變性

函數式編程中函數是一等公民,所以對於數據來說,需要他們是不可變的。另外,對象的不可變確實能夠帶來一些好處,比如:如果數據是不可變的,那麽可以直接通過“===”來判斷數據是否發生變化,這使得react的效率得到極大提升。下面我們來討論在js中實現immutable對象的方法。

freeze

用Object.freeze可以凍結一個數組或者對象,當使用Object.freeze的時候,將導致後續的變化失敗。如果在嚴格模式下使用,將拋出一個TypeError;否則,所有的變化將悄悄地失敗。實例如下:

var a = [2,3,4];
a[1]; //輸出3
Object.freeze(a);
a[1]=5;
a[1]; //輸出3

也有一個isFrozen API來判斷a是否確實被凍結。

Object.isFrozen(a); //輸出true

但是這麽實現有如下幾個痛點:

  1. 變化會悄悄地失敗,可能會導致微妙的錯誤。
  2. 是所有的庫都支持freeze。
  3. 這個是最重要的,Object.freeze是一個淺操作

由於Object.freeze是一個淺操作,所以嵌套對象裏面的變量不會被凍結,除非用遞歸進行深凍結,代碼如下:

function isObject(obj) {
    var type = typeof obj;
    return type === 'function' || type === 'object' && !!obj;
}

function deepFreeze(obj) {
    if(!Object.isFrozen(obj)) Object.freeze(obj);
    for (var key in obj) {
        if(!obj.hasOwnProperty(key) || !isObject(obj)) continue;
        deepFreeze(obj[key];
    }
}

使用容器

我們也可以使用深復制,並把它放在一個容器裏面來保持變量的不變性。簡單代碼如下:

function isObject(obj) {
    var type = typeof obj;
    return type === 'function' || type === 'object' && !!obj;
}

function deepClone(obj) {
    if(!isObject(obj)) return obj;
    var temp = new obj.constructor();
    for (var key in obj) {
        if(obj.hasOwnProperty(key))
            temp[key] = deepClone(obj[key]);
    }
    return temp;
}

function Container(init) {
    this.state = init;
}

Container.prototype = {
    setState: function(obj) {
        this.state = deepClone(obj);
        return this.state;
    }
}

var aObj = new Container({a:{b:1}, c:2});
aObj.setState({a:{b:3}, c:6, d:8});

aObj; //輸出{a:{b:3}, c:6, d:8}

使用immutable.js

使用上面的方法實現不可變數據問題很多,用freeze會悄悄地失敗,並且是淺操作,使用容器的話深復制對象會消耗大量的內存,並且速度很慢。

immutable.js就是facebook開源的為了解決這個問題的庫。它可以說是和react一樣的劃時代的產物。它通過參考hash maps tries和hash maps tries提供了一種優雅地實現javascript Immutable Data的方式。

它使用了Structural Sharing(結構共享),即如果對象樹中一個節點發生變化,只修改這個節點和受它影響的父節點,其它節點則進行共享。所以避免了深拷貝帶來的CPU 和內存的浪費。

具體可參考:
搞定immutable.js詳細說明
IMMUTABLE 詳解

JavaScript 函數式編程讀書筆記2