Live Note

Remain optimistic

  • before: abcd
  • after: acdb

===第一轮遍历开始===

a(之后)vs a(之前)
key 不变,可复用
此时 a 对应的 oldFiber(之前的 a)在之前的数组(abcd)中索引为 0
所以 lastPlacedIndex = 0;

继续第一轮遍历…

c(之后)vs b(之前)
key 改变,不能复用,跳出第一轮遍历
此时 lastPlacedIndex === 0;
===第一轮遍历结束===

===第二轮遍历开始===
newChildren === cdb,没用完,不需要执行删除旧节点
oldFiber === bcd,没用完,不需要执行插入新节点

将剩余 oldFiber(bcd)保存为 map

// 当前 oldFiber:bcd
// 当前 newChildren:cdb

继续遍历剩余 newChildren

key === c 在 oldFiber 中存在
const oldIndex = c(之前).index;
此时 oldIndex === 2; // 之前节点为 abcd,所以 c.index === 2
比较 oldIndex 与 lastPlacedIndex;

如果 oldIndex >= lastPlacedIndex 代表该可复用节点不需要移动
并将 lastPlacedIndex = oldIndex;
如果 oldIndex < lastplacedIndex 该可复用节点之前插入的位置索引小于这次更新需要插入的位置索引,代表该节点需要向右移动

在例子中,oldIndex 2 > lastPlacedIndex 0
lastPlacedIndex = 2;
c 节点位置不变

继续遍历剩余 newChildren

// 当前 oldFiber:bd
// 当前 newChildren:db

key === d 在 oldFiber 中存在
const oldIndex = d(之前).index;
oldIndex 3 > lastPlacedIndex 2 // 之前节点为 abcd,所以 d.index === 3
lastPlacedIndex = 3;
d 节点位置不变

继续遍历剩余 newChildren

// 当前 oldFiber:b
// 当前 newChildren:b

key === b 在 oldFiber 中存在
const oldIndex = b(之前).index;
oldIndex 1 < lastPlacedIndex 3 // 之前节点为 abcd,所以 b.index === 1
则 b 节点需要向右移动
===第二轮遍历结束===

最终 acd 3 个节点都没有移动,b 节点被标记为移动

Class in ES2015

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Class representing a point.
*/
class Point {
/**
* Create a point.
* @param {number} x - The x value.
* @param {number} y - The y value.
*/
constructor(x, y) {}

/**
* Get the x value.
* @return {number} The x value.
*/
getX() {}

/**
* Convert a string containing two comma-separated number into a point.
* @param {string} str - The string containing two comma-separated number.
* @return {Point} A point object.
*/
static fromStringStr(str) {}
}

extends

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Class representing a point.
* @extends Point
*/
class Dot extends Point {
/**
* Create a dot.
* @param {number} x - The x value.
* @param {number} y - The y value.
* @param {number} width - The width of the dot.
*/
constructor(x, y, width) {
super(x, y)
}

/**
* Get the width of the dot.
* @return {number} The dot's width.
*/
getWidth() {}
}

@abstract

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Foo.
* @constructor
*/
function Foo() {}

/**
* Check if is solid.
* @abstract
* @return {boolean}
*/
Foo.prototype.isSolid = function () {
throw new Error("Must be implemented by suclass.")
}

/**
* Bar.
* @constructor
* @arguments Foo
*/
function Bar() {}

/**
* Check if is solid.
* @return {boolean} Always return false.
*/
Bar.prototype.isSolid = function () {
return false
}

@assets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* @constructor
*/
function Foo() {
/**
* @assets private
* @type {number}
*/
let foo = 0

/**
* @assets protected
* @type {string}
*/
this.bar = "1"

/**
* @assets package
* @type {string}
*/
this.barz = "2"

/**
* @assets public
* @type {string}
*/
this.barm = "3"
}

@author

1
2
3
4
/**
* @author Edward <wang.huiyang@outlook.com>
*/
function MyClass() {}

@callback

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @class
*/
function Foo() {}

/**
* Send a request.
* @param {requestCallback} cb - The callback than handles the response.
*/
Foo.prototype.send = function (cb) {}

/**
* Callback
* @callback requestCallback
* @param {number} responseCode
* @param {string} responseMessage
*/

@event

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @constructor
*/
function Foo() {}

/**
* Do some test.
* @fires Foo#test
*/
Foo.prototype.test = function () {}

/**
* Foo test.
* @event Foo#test
* @type {object}
* @property {boolean} isPass - Check if is pass.
*/

Class

1
2
3
4
5
6
7
8
9
10
11
// class factory
function classFactory(phone) {
return class {
getName() {
return phone
}
}
}

let _187 = classFactory("18720128815")
console.log(new _187().getName())

Calculated attribute name

1
2
3
4
5
6
7
class User {
["say" + "Hi"]() {
console.log("hi")
}
}

new User()["sayHi"]

Class field

1
2
3
4
5
6
7
8
// class field
class User {
name = "Edward" // is not at the prototype
}

const user = new User()
console.log(user.name) // Edward
console.log(User.prototype.name) // undefined

Extends — How the super run

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
let animal = {
name: "Animal",
eat() {
console.log(this.name + " eat")
},
}

let rabbit = {
__proto__: animal, // extends animal
eat() {
super.eat()
},
}

let err = {
__proto__: rabbit, // extends rabbit
name: "err obj",
eat() {
super.eat()
},
}

// super.eat() -> [[Rabbit.prototype]].eat
// -> super.eat -> [[Animal.prototype]].eat
// this -> err
err.eat()

class Animal {}
class Rabbit extends Animal {}
console.log(Rabbit.__proto__ === Animal) // class extends link
console.log(Rabbit.prototype.__proto__ === Animal.prototype) // prototype extends link

Prototype

change the basic class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let user = {
name: "Edward",
hello(name) {
console.log(`hi ${this.name}, this is ${name}`)
},
}

Function.prototype.defer = function (ms) {
let f = this
return function (...arg) {
setTimeout(() => f.apply(this, arg), ms)
}
}

user.hello = user.hello.defer(1000)
user.hello("Ejklfj") // will delay 1000ms

Magic of the instance of

1
2
3
4
5
6
7
8
class Animal {
static [Symbol.hasInstance](obj) {
if (obj.canEat) return true
}
}

let obj = { canEat: true }
console.log(obj instanceof Animal) // it will find from the [[Prototype]]

Static

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class User {
static staticMethod() {
console.log(this === User)
}
}

class Article {
constructor(title, date) {
this.title = title
this.date = date
}

static compare(articleA, articleB) {
return articleA.date - articleB.date
}
}

let articles = [
new Article("HTML", new Date(2019, 1, 1)),
new Article("Css", new Date(2019, 0, 1)),
]

articles.sort(Article.compare)
console.log(articles)

e.g.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
let worker = {
someMethod() {
return 1
},

slow(x) {
console.log("called with " + x)
return x * this.someMethod()
},
}

function decorator(func) {
const cache = new Map()

return function (x) {
if (cache.has(x)) {
console.log("cache hit")
return cache.get(x)
}

const result = func.call(this, x)
cache.set(x, result)

return result
}
}

worker.slow = decorator(worker.slow)

console.log(worker.slow(2))
console.log(worker.slow(2))

Injection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function injection(func, ...argsBound) {
return function (...args) {
return func.call(this, ...argsBound, ...args)
}
}

// usage
let user = {
firstName: "Edward",
say(time, phrase) {
console.log(`[${time}]: ${this.firstName} ${phrase}`)
},
}

user.say = injection(
user.say,
new Date().getHours() + ":" + new Date().getMinutes()
)

user.say("Hi")

arrow function

1
2
3
4
5
6
7
8
9
10
11
12
function defer(f, ms) {
return function () {
setTimeout(() => f.apply(this, arguments), ms)
}
}

function sayHello(name) {
console.log(`Hi, ${name}`)
}

const deferSay = defer(sayHello, 2000)
deferSay("Edward")

prototype

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let user = {
name: "Edward",
hello(name) {
console.log(`hi ${this.name}, this is ${name}`)
},
}

Function.prototype.defer = function (ms) {
let f = this
return function (...arg) {
setTimeout(() => f.apply(this, arg), ms)
}
}

user.hello = user.hello.defer(1000)
user.hello("Ejklfj")

Definition

A Fenwick tree or binary indexed tree is a data structure that can efficiently update elements and calculate prefix sums in a table of numbers.

  1. update(index, delta): 将delta加到index位置上。
  2. prefixSum(index): 求 sum[1, index]的值。
  3. rangeSum(from, to): 求 sum[from, to] 的值。

时间复杂度:

  1. update(index, delta): 更新需要循环更新每一个parent的值,从index开始到最后一个parent。复杂度为O(n)
  2. prefixSum(index): 直接返回sum[index + 1]即可,复杂度为O(1)
  3. rangeSum(from, to): 直接返回sum[to + 1] - sum[from]即可,复杂度为O(1)

Build

现在有个nums初始数组,通过这个数组构造一个BITArray
构造Binary Indexed Array

  1. 实现insert(index, delta):
1
2
3
4
5
6
function insert(index, delta) {
while (index < this.BITArray.length) {
this.BITArray[index] += delta
index += index & -index // BIT中,parent的index计算方法为:parent = child + (child & -child)
}
}
  1. 构造 BITArray:
1
2
3
4
5
6
function MyArray(nums) {
this.BITArray = new Array(nums.length + 1).fill(0)
for (let i = 0, len = nums.length; i < len; i++) {
this.insert(i + 1, nums[i]) // 在每个index处循环插入,delta就是初始值。
}
}
  1. 实现sum(index):
1
2
3
4
5
6
7
8
9
function sum(index) {
let sum = 0
while (index > 0) {
sum += this.BITArray[index]
index -= index & -index // BIT中,child的计算方法为:child = parent - (parent & -parent)
}

return sum
}
  1. 实现perfixSum(from, to)
1
2
3
function perfixSum(from, to) {
return this.sum(to + 1) - this.sum(from)
}

parseInt 中塞 number

1
2
parseInt(0.000001) // 0
parseInt(0.0000001) // 1

为什么会得到这样的结果?

  1. parseInt(arg: string):接收的是一个string变量。
  2. 0.0000001转成string会变为1e-7
  3. parseInt('1e-7')结果为1

所以要截取小数,最好还是使用Math.trunc(n)

1
2
3
4
5
6
7
8
9
10
const enum Foo {
AA = "aa",
BB = "bb",
}

type B = keyof typeof Foo // 'AA' | 'BB'

// Template Literal Types
type C = `${keyof { [x in Foo]: string }}`
// 'aa' | 'bb'

缘由

公司的 PC 没有音卡。导致耳机不能播放。

使用 pavucontrol 输出为模拟信号

刚开始总报找不到这个 package。
换了官方源也没用。
后来才发现需要打开开源 package 安装。。。software & updates > ubuntu software > open-source software

天下无不散的宴席

实习生只剩下一个了,其他都离职了。对他们来说是件好事,呆在这里也不能提高多少。

最近发生的事情太多了:

  • 养了一只猫:某天突然就想养只猫了,下午决定晚上就去领了一只。回家后花了不少精力,现在活得还算不错。
  • 新买了个镜头:入了个 35mm f2.0 镜头,扫街+人像应该够了。
  • 不知不觉喜欢上了一个女生:深入了解后发现希望不大,还是放弃了。
  • 去了家公司参观:这家公司有 Node 中间层,是以前未接触过的。今后还需努力。
  • 刷了一点 leetcode:在公司需求不多,就刷着为以后做准备了。
  • 买了一点书:身体和心灵总有一个在路上。
  • 去桂山岛旅游:看了看人烟稀少的小镇是什么样的生活。

币圈疯狂的人们

数字货币的世界,涨跌不需要理由。
公司一群人炒币,只有一个人脱身,其余的加起来估计亏了百来万。
地铁上,公交上,餐厅奶茶店;俊男靓女,大爷大妈,所有人都在炒币,太疯狂了。

人的欲望总是无穷的,赌徒只需要输一次就能将所有的钱输完,人性的弱点。
大家都希望山底买,山顶卖。但是谁又知道你是不是买在山顶呢。大家都信仰最大傻瓜理论,觉得自己不是那个大傻瓜。

安心生活

周末出去走走看看世界
看一场电影
看几本书
与朋友游戏几局
平安喜乐就够了

还是决定关闭 blog 了。

太多黑历史,何况还有骂 GCD 的东西。

Null-aware operators

1
2
3
4
5
6
7
8
9
10
String foo = 'a string';
String bar; // Unassigned objects are null by default.

// Substitute an operator that makes 'a string' be assigned to baz.
String baz = foo ?? bar;

void updateSomeVars() {
// Substitute an operator that makes 'a string' be assigned to bar.
bar ??= 'a string';
}

Conditional property access

myObject?.someProperty equals to (myObject != null) ? myObject.someProperty : null.

1
2
3
4
5
6
// This method should return the uppercase version of `str`
// or null if `str` is null.
String upperCaseIt(String str) {
// Try conditionally accessing the `toUpperCase` method here.
return str?.toUpperCase();
}

Cascades

myObject.someMethod() will get the return value of the someMethod(), myObject..someMethod() will get the reference of the myObject.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class BigObject {
int anInt = 0;
String aString = '';
List<double> aList = [];
bool _done = false;

void allDone() {
_done = true;
}
}

BigObject fillBigObject(BigObject obj) {
// Create a single statement that will update and return obj:
return obj
..anInt = 1
..aString = "String!"
..aList = [3.0]
..allDone();
}
Read more »