成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Immutable.js 初識(shí)

Olivia / 3274人閱讀

摘要:文章博客地址所創(chuàng)建的數(shù)據(jù)有一個(gè)迷人的特性數(shù)據(jù)創(chuàng)建后不會(huì)被改變。是的基類(lèi),使用該類(lèi)時(shí)需要至少繼承其子類(lèi)中的一個(gè)。總結(jié)所提供的和固有的各有優(yōu)勢(shì),未來(lái)有可能制定一套原生的規(guī)范,在這之前,是一個(gè)不錯(cuò)的選擇。參考資料官方文檔

文章博客地址:http://pinggod.com/2016/Immutable/

Immutable.js 所創(chuàng)建的數(shù)據(jù)有一個(gè)迷人的特性:數(shù)據(jù)創(chuàng)建后不會(huì)被改變。我們使用 Immutable.js 的示例來(lái)解釋這一特性:

var Immutable = require("immutable");

var map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set("b", 50);

map1.get("b"); // 2
map2.get("b"); // 50

在上面代碼第三行中,map1 使用 set 方法更新數(shù)據(jù),結(jié)果返回一個(gè)新的 Map 類(lèi)型數(shù)據(jù) map2,map2 包含了更新后的數(shù)據(jù),但是 map1 沒(méi)有發(fā)生變化。這種特性讓我們?cè)谝脭?shù)據(jù)的時(shí)候毫無(wú)后顧之憂,因?yàn)槿魏螌?duì)數(shù)據(jù)的修改都不會(huì)影響最原始的數(shù)據(jù)。在 Immutable.js 誕生之前,我們可以使用深拷貝的方式模擬這一特性,但是會(huì)耗費(fèi)過(guò)多的內(nèi)存空間和計(jì)算力。Immutable.js 相比深拷貝的優(yōu)勢(shì)在于區(qū)分發(fā)生變化的數(shù)據(jù)和未變化的數(shù)據(jù),對(duì)于上面的 map1 和 map2,b 是變化的數(shù)據(jù),所以 map1 和 map2 各保存一份 b 數(shù)據(jù),而 ac 是未變化的數(shù)據(jù),所以 map1 和 map2 仍然共享 ac 的數(shù)據(jù)。

概覽

Immutable Data 鼓勵(lì)開(kāi)發(fā)者使用純函數(shù)式的開(kāi)發(fā)方式,并從函數(shù)式開(kāi)發(fā)中引入了惰性計(jì)算的特性。雖然加入了很多函數(shù)式的概念,Immutable.js 仍然提供了類(lèi)似原生 JavaScript Array、Map 和 Set 中的方法,并且提供了在原生 JavasScript 數(shù)據(jù)和 Immutable 數(shù)據(jù)之間快速轉(zhuǎn)換的機(jī)制。

Immutable.js 的 API 主要包含以下幾部分:

formJS(),將 JavaScript Object 和 Array 徹底轉(zhuǎn)換為 Immutable Map 和 List

is(),與 Object.is() 類(lèi)似都是對(duì)值的比較,但它會(huì)將 Immutable Iterable 視為值類(lèi)型數(shù)據(jù)而不是引用類(lèi)型數(shù)據(jù),如果兩個(gè) Immutable Iterable 的值相等,則返回 true。與 Object.is() 不同的是,is(0, -0) 的結(jié)果為 true

List,有序索引集,類(lèi)似于 JavaScript 中的 Array

Map,無(wú)序 Iterable,讀寫(xiě) Key 的復(fù)雜度為 O(log32 N)

OrderedMap,有序 Map,排序依據(jù)是數(shù)據(jù)的 set() 操作

Set,元素為獨(dú)一無(wú)二的集合,添加數(shù)據(jù)和判斷數(shù)據(jù)是否存在的復(fù)雜度為 O(log32 N)

OrderedSet,有序 Set,排序依據(jù)是數(shù)據(jù)的 add 操作。

Stack,有序集合,且使用 unshift(v)shift() 進(jìn)行添加和刪除操作的復(fù)雜度為 O(1)

Range(),返回一個(gè) Seq.Indexed 類(lèi)型的數(shù)據(jù)集合,該方法接收三個(gè)參數(shù) (start = 1, end = infinity, step = 1),分別表示起始點(diǎn)、終止點(diǎn)和步長(zhǎng),如果 start 等于 end,則返回空的數(shù)據(jù)結(jié)合

Repeat(),返回一個(gè) Seq.indexed 類(lèi)型的數(shù)據(jù)結(jié)合,該方法接收兩個(gè)參數(shù) (value,times),value 表示重復(fù)生成的值,times 表示重復(fù)生成的次數(shù),如果沒(méi)有指定 times,則表示生成的 Seq 包含無(wú)限個(gè) value

Record,用于衍生新的 Record 類(lèi),進(jìn)而生成 Record 實(shí)例。Record 實(shí)例類(lèi)似于 JavaScript 中的 Object 實(shí)例,但只接收特定的字符串作為 key,且擁有默認(rèn)值

Seq,序列(may not be backed by a concrete data structure)

Iterable,可以被迭代的 (Key, Value) 鍵值對(duì)集合,是 Immutable.js 中其他所有集合的基類(lèi),為其他所有集合提供了 基礎(chǔ)的 Iterable 操作函數(shù)(比如 map()filter

Collection,創(chuàng)建 Immutable 數(shù)據(jù)結(jié)構(gòu)的最基礎(chǔ)的抽象類(lèi),不能直接構(gòu)造該類(lèi)型

1. fromJS()
Immutable.fromJS({a: {b: [10, 20, 30]}, c: 40}, function (key, value) {
    var isIndexed = Immutable.Iterable.isIndexed(value);
    return isIndexed ? value.toList() : value.toOrderedMap();
});
// true, "b", {b: [10, 20, 30]}
// false, "a", {a: {b: [10, 20, 30]}, c: 40}
// false, "", {"": {a: {b: [10, 20, 30]}, c: 40}}

fromJS() 的使用方式類(lèi)似于 JSON.parse(),接收兩個(gè)參數(shù):json 數(shù)據(jù)和 reviver 函數(shù)。

2. List
List(): List
List(iter: Iterable.Indexed): List
List(iter: Iterable.Set): List
List(iter: Iterable.Keyed): List
List(array: Array): List
List(iterator: Iterator): List
List(iterable: Object): List

List() 是一個(gè)構(gòu)造方法,可以用于創(chuàng)建新的 List 數(shù)據(jù)類(lèi)型,上面代碼演示了該構(gòu)造方法接收的參數(shù)類(lèi)型,此外 List 擁有兩個(gè)靜態(tài)方法:

List.isList(value),判斷 value 是否是 List 類(lèi)型

List.of(...values),創(chuàng)建包含 ...values 的列表

下面演示幾個(gè) List 常用的操作,更詳細(xì)的 API 說(shuō)明請(qǐng)參考官方文檔:

// 1. 查看 List 長(zhǎng)度
const $arr1 = List([1, 2, 3]);
$arr1.size
// => 3

// 2. 添加或替換 List 實(shí)例中的元素
// set(index: number, value: T)
// 將 index 位置的元素替換為 value,即使索引越界也是安全的
const $arr2 = $arr1.set(-1, 0);
// => [1, 2, 0]
const $arr3 = $arr1.set(4, 0);
// => [ 1, 2, 3, undefined, 0 ]

// 3. 刪除 List 實(shí)例中的元素
// delete(index: number)
// 刪除 index 位置的元素
const $arr4 = $arr1.delete(1);
// => [ 1, 3 ]

// 4. 向 List 插入元素
// insert(index: number, value: T)
// 向 index 位置插入 value
const $arr5 = $arr1.insert(1, 1.5);
// => [ 1, 1.5, 2, 3 ]

// 5. 清空 List
// clear()
const $arr6 = $arr1.clear();
// => []
3. Map

Map 可以使用任何類(lèi)型的數(shù)據(jù)作為 Key 值,并使用 Immutable.is() 方法來(lái)比較兩個(gè) Key 值是否相等:

Map().set(List.of(1), "listofone").get(List.of(1));
// => "listofone"

但是使用 JavaScript 中的引用類(lèi)型數(shù)據(jù)(對(duì)象、數(shù)組)作為 Key 值時(shí),雖然有時(shí)兩個(gè) Key 很像,但它們也是兩個(gè)不同的 Key 值:

console.log(Map().set({}, 1).get({}))
// => undefined

Map() 是 Map 類(lèi)型的構(gòu)造方法,行為類(lèi)似于 List(),用于創(chuàng)建新的 Map 實(shí)例,此外,還包含兩個(gè)靜態(tài)方法:Map.isMap() 和 Map.of()。下面介紹幾個(gè) Map 實(shí)例的常用操作,更詳細(xì)的 API 使用說(shuō)明請(qǐng)參考官方文檔:

// 1. Map 實(shí)例的大小
const $map1 = Map({ a: 1 });
$map1.size
// => 1

// 2. 添加或替換 Map 實(shí)例中的元素
// set(key: K, value: V)
const $map2 = $map1.set("a", 2);
// => Map { "a": 2 }

// 3. 刪除元素
// delete(key: K)
const $map3 = $map1.delete("a");
// => Map {}

// 4. 清空 Map 實(shí)例
const $map4 = $map1.clear();
// => Map {}

// 5. 更新 Map 元素
// update(updater: (value: Map) => Map)
// update(key: K, updater: (value: V) => V)
// update(key: K, notSetValue: V, updater: (value: V) => V)
const $map5 = $map1.update("a", () => (2))
// => Map { "a": 2 }

// 6. 合并 Map 實(shí)例
const $map6 = Map({ b: 2 });
$map1.merge($map6);
// => Map { "a": 1, "b": 2 }

OrderedMap 是 Map 的變體,它除了具有 Map 的特性外,還具有順序性,當(dāng)開(kāi)發(fā)者遍歷 OrderedMap 的實(shí)例時(shí),遍歷順序?yàn)樵搶?shí)例中元素的聲明、添加順序。

4. Set

Set 和 ES6 中的 Set 類(lèi)似,都是沒(méi)有重復(fù)值的集合,OrderedSet 是 Set 的遍歷,可以保證遍歷的順序性。

// 1. 創(chuàng)建 Set 實(shí)例
const $set1 = Set([1, 2, 3]);
// => Set { 1, 2, 3 }

// 2. 添加元素
const $set2 = $set1.add(1).add(4);
// => Set { 1, 2, 3, 4 }

// 3. 刪除元素
const $set3 = $set1.delete(3);
// => Set { 1, 2 }

// 4. 并集
const $set4 = Set([2, 3, 4, 5, 6]);
$set1.union($set1);
// => Set { 1, 2, 3, 4, 5, 6 }

// 5. 交集
$set1.intersect($set4);
// => Set { 3, 2 }

// 6. 差集
$set1.subtract($set4);
// => Set { 1 }
5. Stack

Stack 是基于 Signle-Linked List 實(shí)現(xiàn)的可索引集合,使用 unshift(v)shift() 執(zhí)行添加和刪除元素的復(fù)雜度為 O(1)。

// 1. 創(chuàng)建 Stack 實(shí)例
const $stack1 = Stack([1, 2, 3]);
// => Stack [ 1, 2, 3 ]

// 2. 取第一個(gè)元素
$stack1.peek()
// => 1

// 2. 取任意位置元素
$stack1.get(2)
// => 3

// 3. 判斷是否存在
$stack1.has(10)
// => false
6. Range() 和 Repeat()

Range(start?, end?, step?) 接收三個(gè)可選參數(shù),使用方法如下:

// 1. 不傳參
Range();
// => Range [ 0...Infinity ]

// 2. 設(shè)置 start 起點(diǎn)
Range(10);
// => Range [ 10...Infinity ]

// 3. 設(shè)置 start 起點(diǎn)和 end 終點(diǎn)
Range(10, 20);
// => Range [ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ]

// 4. 設(shè)置 start 起點(diǎn)、end 終點(diǎn)和 step 步長(zhǎng)
Range(10, 20, 3);
// => Range [ 10, 13, 16, 19 ]

Repeat(value, times?) 接收兩個(gè)參數(shù),其中 times 重復(fù)次數(shù)是可選參數(shù):

Repeat("foo");
// => Repeat [ foo Infinity times ]

Repeat("foo", 3);
// => Repeat [ foo 3 times ]

類(lèi)似 Range()Repeat(value) 這樣生成無(wú)限長(zhǎng)度集合的操作,內(nèi)部都存在惰性計(jì)算的機(jī)制,只有真實(shí)取值時(shí)才會(huì)生成相應(yīng)的結(jié)果。使用 ES6 中的 Generator 函數(shù),可以輕松實(shí)現(xiàn)一個(gè)惰性計(jì)算:

function* bigArr() {
    for (let i = 0; i < 100000; i++) {
        console.log(`bigArr(${i}): ${i}`)
        yield i;
    }
}

const arr = bigArr();

for (let i = 0; i < 10; i++) {
    console.log(arr.next());
}
// bigArr(0): 0
// => { value: 0, done: false }
// => bigArr(1): 1
// => { value: 1, done: false }
// => bigArr(2): 2
// => { value: 2, done: false }
// => bigArr(3): 3
// => { value: 3, done: false }
// => bigArr(4): 4
// => { value: 4, done: false }
// => bigArr(5): 5
// => { value: 5, done: false }
// => bigArr(6): 6
// => { value: 6, done: false }
// => bigArr(7): 7
// => { value: 7, done: false }
// => bigArr(8): 8
// => { value: 8, done: false }
// => bigArr(9): 9
// => { value: 9, done: false }
7. Record

Record 在表現(xiàn)上類(lèi)似于 ES6 中的 Class,但在某些細(xì)節(jié)上還有所不同。通過(guò) Record() 可以創(chuàng)建一個(gè)新的 Record 類(lèi),使用該類(lèi)可以創(chuàng)建具體的 Record 實(shí)例,該實(shí)例包含在 Record() 構(gòu)造函數(shù)中聲明的所有屬性和默認(rèn)值。如果 Record 實(shí)例中的某個(gè)屬性被刪除了,則只會(huì)講實(shí)例中的屬性值恢復(fù)為默認(rèn)值:

// 1. 創(chuàng)建 Record 實(shí)例
const A = Record({ a: 1, b: 2 });
const r = new A({ a: 3 });
// => Record { "a": 3, "b": 2 }

// 2. 刪除實(shí)例屬性
const rr = r.remove("a");
// => Record { "a": 1, "b": 2 }

此外,Record 實(shí)例還具有擴(kuò)展性:

class ABRecord extends Record({a:1,b:2}) {
  getAB() {
    return this.a + this.b;
  }
}

var myRecord = new ABRecord({b: 3})
myRecord.getAB()
// => 4
8. Seq

Seq 有兩個(gè)特點(diǎn):immutable,一旦創(chuàng)建就不能被修改;lazy,惰性求值。在下面的代碼中,雖然組合了多種遍歷操作,但實(shí)際上并不會(huì)有任何的求值操作,只是純粹的聲明一個(gè) Seq:

var oddSquares = Immutable.Seq.of(1,2,3,4,5,6,7,8)
    .filter(x => x % 2)
    .map(x => x * x);

如果要從 oddSquares 中取出索引為 1 的元素,則執(zhí)行過(guò)程為:

console.log(oddSquares.get(1));

// filter(1)
// filter(2)
// filter(3)
// map(3)
// => 9

Seq() 是 Seq 的構(gòu)造方法,它根據(jù)傳入的參數(shù)類(lèi)型,輸出響應(yīng)的 Seq 類(lèi)型:

輸入 Seq,輸出 Seq

輸入 Iterable,輸出同類(lèi)型的 Seq(Keyed, Indexed, Set)

輸入 Array-like,輸出 Seq.Indexed

輸入附加 Iterator 的 Object,輸出 Seq.Indexed

輸入 Iterator,輸出 Seq。indexed

輸入 Object,輸出 Seq.Keyed

默認(rèn)情況下 Seq 的惰性計(jì)算結(jié)果不會(huì)被緩存,比如在下面的代碼中,由于每個(gè) join() 都會(huì)遍歷執(zhí)行 map,所以 map 總共執(zhí)行了六次:

var squares = Seq.of(1,2,3).map(x => x * x);
squares.join() + squares.join();

如果開(kāi)發(fā)者知道 Seq 的結(jié)果會(huì)被反復(fù)用到,那么就可以使用 cacheResult() 將惰性計(jì)算的結(jié)果保存到內(nèi)存中:

var squares = Seq.of(1,2,3).map(x => x * x).cacheResult();
squares.join() + squares.join();
9. Iterable 和 Collection

Iterable 是鍵值對(duì)形式的集合,其實(shí)例可以執(zhí)行遍歷操作,是 immutable.js 中其他數(shù)據(jù)類(lèi)型的基類(lèi),所有擴(kuò)展自 Iterable 的數(shù)據(jù)類(lèi)型都可以使用 Iterable 所聲明的方法,比如 map 和 filter 等。

Collection 是 Concrete Data Structure 的基類(lèi),使用該類(lèi)時(shí)需要至少繼承其子類(lèi)中的一個(gè):Collection.Keyed / Collection.Indexed / Collection.Set。

React

在 React 官方文檔的《Advanced Performance》 一節(jié)中,專門(mén)對(duì) React 的性能瓶頸、優(yōu)化方式做了詳細(xì)的解析。當(dāng)一個(gè) React 組件的 props 和 state 發(fā)生變化時(shí),React 會(huì)根據(jù)變化后的 props 和 state 創(chuàng)建一個(gè)新的 virtual DOM,然后比較新舊兩個(gè) vritual DOM 是否一致,只有當(dāng)兩者不同時(shí),React 才會(huì)將 virtual DOM 渲染真實(shí)的 DOM 結(jié)點(diǎn),而對(duì) React 進(jìn)行性能優(yōu)化的核心就是減少渲染真實(shí) DOM 結(jié)點(diǎn)的頻率,間接地指出開(kāi)發(fā)者應(yīng)該準(zhǔn)確判斷 props 和 state 是否真正發(fā)生了變化。

在比對(duì)新舊 vritual DOM 和渲染真實(shí) DOM 前,React 為開(kāi)發(fā)者提供了 shouldComponentUpdate() 方法中斷接下來(lái)的比對(duì)和渲染操作,默認(rèn)情況下,該方法總會(huì)返回 true,如果它返回 false,則不執(zhí)行比對(duì)和渲染操作:

// 最簡(jiǎn)單的實(shí)現(xiàn):
shouldComponentUpdate (nextProps) {
    return this.props.value !== nextProps.value;
}

看起來(lái)挺簡(jiǎn)單,實(shí)在不然。當(dāng)我們需要比對(duì)的值是對(duì)象、數(shù)組等引用值時(shí),就會(huì)出現(xiàn)問(wèn)題:

// 假設(shè) this.props.value 是 { foo: "bar" }
// 假設(shè) nextProps.value 是 { foo: "bar" },
// 顯然這兩者引用的內(nèi)存地址不同,但它們具有相同的值,這種時(shí)候不應(yīng)該繼續(xù)執(zhí)行渲染
this.props.value !== nextProps.value; // true

如果數(shù)據(jù)是 Immutable Data 的話,那么數(shù)據(jù)發(fā)生變化就會(huì)生成新的對(duì)象,開(kāi)發(fā)者只需要檢查對(duì)象應(yīng)用是否發(fā)生變化即可:

var SomeRecord = Immutable.Record({ foo: null });
var x = new SomeRecord({ foo: "bar"  });
var y = x.set("foo", "baz");
x === y; // false

處理這一問(wèn)題的另一種方式是通過(guò) setter 設(shè)置 flag 對(duì)臟數(shù)據(jù)進(jìn)行檢查,但冗雜的代碼是在讓人頭疼。

總結(jié)

Immutable.js 所提供的 Immutable Data 和 JavaScript 固有的 Mutable Data 各有優(yōu)勢(shì),未來(lái) ECAMScript 有可能制定一套原生的 Immutable Data 規(guī)范,在這之前,Immutable.js 是一個(gè)不錯(cuò)的選擇。之前已經(jīng)寫(xiě)文章熟悉過(guò) Lodash 這一工具庫(kù),Immutable 內(nèi)部也封裝了諸多常用的數(shù)據(jù)操作函數(shù),所以如果讓我來(lái)選擇的話,在 React 技術(shù)棧中我會(huì)更偏愛(ài) Immutable。

參考資料

Immutable.js 官方文檔

React: Advanced Performance

Introduction to Immutable.js and Functional Programming Concepts

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/79959.html

相關(guān)文章

  • immutable.js初識(shí)

    摘要:介紹按照官網(wǎng)的定義是指一旦被創(chuàng)造后,就不可以被改變的數(shù)據(jù)。很多場(chǎng)景下,對(duì)于屬性相同的對(duì)象,我們希望相等性判斷為。和都有一個(gè)名為方法,用來(lái)處理深度對(duì)象的比較。之于的好處眾所周知,性能優(yōu)化的核心在于處理方法來(lái)避免不必要的渲染。 介紹 按照官網(wǎng)的定義, Immutable Data是指一旦被創(chuàng)造后,就不可以被改變的數(shù)據(jù)。 相等性判斷 JavaScript提供三種不同的值比較操作: 嚴(yán)格相等...

    AdolphLWQ 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.16 - 淺入淺出 JavaScript 函數(shù)式編程

    摘要:函數(shù)式編程,一看這個(gè)詞,簡(jiǎn)直就是學(xué)院派的典范。所以這期周刊,我們就重點(diǎn)引入的函數(shù)式編程,淺入淺出,一窺函數(shù)式編程的思想,可能讓你對(duì)編程語(yǔ)言的理解更加融會(huì)貫通一些。但從根本上來(lái)說(shuō),函數(shù)式編程就是關(guān)于如使用通用的可復(fù)用函數(shù)進(jìn)行組合編程。 showImg(https://segmentfault.com/img/bVGQuc); 函數(shù)式編程(Functional Programming),一...

    csRyan 評(píng)論0 收藏0
  • 深入理解js

    摘要:詳解十大常用設(shè)計(jì)模式力薦深度好文深入理解大設(shè)計(jì)模式收集各種疑難雜癥的問(wèn)題集錦關(guān)于,工作和學(xué)習(xí)過(guò)程中遇到過(guò)許多問(wèn)題,也解答過(guò)許多別人的問(wèn)題。介紹了的內(nèi)存管理。 延遲加載 (Lazyload) 三種實(shí)現(xiàn)方式 延遲加載也稱為惰性加載,即在長(zhǎng)網(wǎng)頁(yè)中延遲加載圖像。用戶滾動(dòng)到它們之前,視口外的圖像不會(huì)加載。本文詳細(xì)介紹了三種延遲加載的實(shí)現(xiàn)方式。 詳解 Javascript十大常用設(shè)計(jì)模式 力薦~ ...

    caikeal 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

Olivia

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<