引用计数的工做原理:设置对象的引用数,有一个引用计数器来维护这些引用数,引用关系改变时修改引用数。判断当前对象引用数是否为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) 算法
回收细节说明
细节对比