引用計數的工做原理:設置對象的引用數,有一個引用計數器來維護這些引用數,引用關係改變時修改引用數。判斷當前對象引用數是否爲0,引用數爲0時當即回收。javascript
引用計數算法優勢:java
引用計數算法缺點:web
標記整理算法工做流程:算法
標記整理算法優缺點:數據庫
新生代存儲區垃圾回收流程:編程
增量標記算法:將一整段的垃圾回收操做,拆分紅多個小步,組合完成整個垃圾回收操做。咱們知道,當垃圾回收工做的時候,會阻塞JS程序執行,當咱們須要優化垃圾回收的效率時,就可使用增量標記算法。數組
優勢:讓垃圾回收與程序執行能夠交替完成,讓時間消耗更合理,達到效率優化的好處。瀏覽器
工做原理:緩存
基於如下代碼完成下面的練習性能優化
const fp = require('lodash/fp'); // 數據 // horsepower 馬力,dollar_value 價格, in_stock 庫存 const cars = [ { name: "Ferrari FF", horsepower: 660, dollar_value: 700000, in_stock: true }, { name: "Spyker Cl2 Zagato", horsepower: 650, dollar_value: 648000, in_stock: false }, { name: "Jaguar XKR-S", horsepower: 550, dollar_value: 132000, in_stock: false } , { name: "Audi R8", horsepower: 525, dollar_value: 114200, in_stock: false }, { name: "Aston Martin One-77", horsepower: 750, dollar_value: 1850000, in_stock: true }, { name: "Pagani Huayra" , horsepower: 700, dollar_value: 1300000, in_stock: false } ];
使用函數組合 fp.flowRight() 從新實現下面這個函數
let isLastInStock = function(cars) { // 獲取最後一條數據 let last_car = fp.last(cars); // 獲取最後一條數據的 in_stock 屬性值 return fp.prop('in_stock', last_car); }
答:
let isLastInStock = fp.flowRight(fp.prop('in_stock'), fp.last) console.log(isLastInStock(cars)); // false
使用 fp.flowRight(), fp.prop() 和 fp.first() 獲取第一個 car 的 name
答:
let getFirstCarName = fp.flowRight(fp.prop('name'), fp.first); console.log(getFirstCarName(cars)); // Ferrari FF
使用幫助函數 _average 重構 averageDollarValue ,使用函數組合的方式實現
// _average 無需改動 let _average = function(xs) { return fp.reduce(fp.add, 0, xs) / xs.length; } let averageDollarValue = function(cars) { let dollar_values = fp.map(function(car) { return car.dollar_value }, cars); return _average(dollar_values); }
答:
let averageDollarValue = fp.flowRight(_average, fp.map(car => car.dollar_value)); console.log(averageDollarValue(cars)); // 790700
使用 flowRight 寫一個 sanitizeNames() 函數,返回一個下劃線鏈接的小寫字符串,把數組中的 name 轉換爲這種形式:例如:sanitizeNames(["Hello World"]) => ["hello_world"]
let _underscore = fp.replace(/\W+/g, '_'); // 無需改動,並在 sanitizeNames 中使用它
答:
let sanitizeNames = fp.flowRight(fp.map(fp.flowRight(_underscore, fp.toLower))); console.log(sanitizeNames(["Hello World"])); // [ 'hello_world' ] console.log(sanitizeNames(["Hello World", "I am Lxcan"])); // [ 'hello_world', 'i_am_lxcan' ]
基於下面提供的代碼,完成後續的練習
// support.js class Container { static of (value) { return new Container(value); } constructor (value) { this._value = value; } map (fn) { return Container.of(fn(this._value)); } } class Maybe { static of (x) { return new Maybe(x); } isNothing () { return this._value === null || this._value === undefined; } constructor (x) { this._value = x; } map (fn) { return this.isNothing() ? this : Maybe.of(fn(this._value)); } } module.exports = { Maybe, Container }
使用 fp.add(x, y) 和 fp.map(f, x) 建立一個能讓 functor 裏的值增長的函數 ex1
const fp = require('lodash/fp'); const { Maybe, Container } = require('./support.js'); let maybe = Maybe.of([5, 6, 1]); // let ex1 = // ... 你須要實現的位置
答:
// let ex1 = fp.flowRight(fp.map(v => fp.add(v, 1))); // console.log(maybe.map(ex1)); // Maybe { _value: [ 6, 7, 2 ] } let ex1 = n => maybe.map(arr => fp.map(v => fp.add(v, n), arr)); console.log(ex1(1)); // 數組每一項加1 // Maybe { _value: [ 6, 7, 2 ] }
實現一個函數 ex2,可以使用 fp.first 獲取列表的第一個元素
const fp = require('lodash/fp'); const { Maybe, Container } = require('./support.js'); let xs = Container.of(['do', 'ray', 'me', 'fa', 'so', 'la', 'ti', 'do']); // let ex2 = // ... 你須要實現的位置
答:
let ex2 = fn => xs.map(fn)._value; console.log(ex2(fp.first)); // "do"
實現一個函數 ex3 ,使用 safeProp 和 fp.first 找到 user 的名字的首字母
const fp = require('lodash/fp'); const { Maybe, Container } = require('./support.js'); let safeProp = fp.curry(function (x, o) { return Maybe.of(o[x]); }); let user = { id: 2, name: 'Albert' }; // let ex3 = // ... 你須要實現的位置
答:
let ex3 = () => safeProp('name', user).map(fp.first)._value; console.log(ex3()); // A
使用 Maybe 重寫 ex4 ,不要有 if 語句
const fp = require('lodash/fp'); const { Maybe, Container } = require('./support.js'); let ex4 = function (n) { if (n) { return parseInt(n) } }
答:
let ex4 = n => Maybe.of(n).map(parseInt)._value; console.log(ex4('100')); // 100
函數式編程就是對運算過程的抽象,其中的函數是指數學中的函數即映射關係,相同的輸入始終要獲得相同的輸出(純函數)。
函數是一等公民是咱們後面要學習的高階函數、柯里化等的基礎
使用高階函數的意義:
能夠在另外一個做用域中調用一個函數的內部函數並訪問到該函數做用域中的成員
閉包的本質:函數在執行的時候會放到一個執行棧上,當函數執行完畢以後會從執行棧上移除,可是堆上的做用域成員由於被外部引用不能釋放,所以內部函數依然能夠訪問外部函數的成員。
相同的輸入永遠會獲得相同的輸出,並且沒有任務可觀察的反作用。
純函數的好處:
反作用讓一個函數變得不純,若是函數依賴於外部的狀態就沒法保證輸出相同,就會帶來反作用。
反作用來源:
總結:
函數組合(compose):若是一個函數要通過多個函數處理才能獲得最終值,這個時候能夠把中間過程的函數合併成一個函數
函數組合要知足結合律(associativity)
咱們既能夠把 g 和 h 組合,還能夠把 f 和 g 組合,結果都是同樣的
let f = compose(f, g, h) let associative = compose(compose(f, g), h) == compose(f, compose(g, h)); // true
咱們能夠把數據處理的過程定義成與數據無關的合成運算,不須要用到表明數據的那個參數,只要把簡單的運算步驟合成到一塊兒,在使用這種模式以前咱們須要定義一些輔助的基本運算函數。
什麼是函子?
MayBe 函子
Either 函子
IO 函子
folktale
Pointed 函子
Monad 函子
介紹
JavaScript 中的垃圾
JavaScript 中的可達對象
引用計數算法優勢:
引用計數算法缺點:
標記清除算法優勢:
標記清除算法缺點:
標記整理算法優缺點:
V8 中經常使用的 GC(Garbage Collection) 算法
回收細節說明
細節對比