Live Note

Remain optimistic

写题时遇见的一个东西

1
2
3
char* s = "hello world";
printf("%15.2s", s);
//result: he

找到如下用法:

  • *%ms:输出的字符串占 m 列,如字符串本身长度大于 m,则突破获 m 的限制,将字符串全部输出。若串长小于 m,则左补空格。
  • *%-ms:如果串长小于 m,则在 m 列范围内,字符串向左靠,右补空格。
  • *%m.ns:输出占 m 列,但只取字符串中左端 n 个字符。这 n 个字符输出在 m 列的右侧,左补空格,注意:如果 n 未指定,默认为 0.
  • *%-m.ns:其中 m、n 含义同上,n 个字符输出在 m 列范围的左侧,右补空格。如果 n>m,则自动取 n 值,即保证 n 个字符正常输出,注意:如果 n 未指定,默认为 0.

如果是 sprintf(desc, “%m.ns”, sour);

  • 如果 desc 空间够的话,会在%m.ns 串 的结尾自动补 null 字符,不同于 strncpy.例如 :sprintf(desc, “%.3s”, “123456”);
  • desc 如果空间>=4 字节的话,第 4 个字节将是 null 字符。

一个简单的处理 XML 的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function parseXml(xml) {
//跨浏览器处理 XML
var xmldom = null

if (typeof DOMParser != "undefined") {
xmldom = new DOMParser().parseFromString(xml, "text/xml")
var errors = xmldom.getElementsByTagName("parsererror")
if (errors.length) {
throw new Error("XML parsing error:" + errors[0].textContent)
}
} else if (typeof ActiveXObject != "undefined") {
xmldom = createDocument()
xmldom.loadXML(xml)
if (xmldom.parseError != 0) {
throw new Error("XML parsing error:" + xmldom.parseError.reason)
}
} else {
throw new Error("No XML parser available.")
}
return xmldom
}

序列化 XML 文档

1
2
3
4
5
6
7
8
9
10
11
12
13
//序列化 xmldom 文档
function serializeXML(xmldom) {
if (typeof XMLSerializer != "undefined") {
//兼容 ie9+ safari Chrome opera
var serializer = new XMLSerializer()
return serializer.serializeToString(xmldom)
} else if (typeof xmldom.xml != undefined) {
//兼容 ie9.0 以下
return xmldom.xml
} else {
throw new Error("serialize XML Dom failed!")
}
}

EventUtil

为了在不同的浏览器中处理相同的事件,需要编写一段可以兼容大部分浏览器的代码。

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
var EventUtil = {
addHandler: function (element, type, handler) {
//添加事件
if (element.addEventListener) {
element.addEventListener(type, handler, false) //使用DOM2级方法添加事件
} else if (element.attachEvent) {
//使用IE方法添加事件
element.attachEvent("on" + type, handler)
} else {
element["on" + type] = handler //使用DOM0级方法添加事件
}
},

removeHandler: function (element, type, handler) {
//取消事件
if (element.removeEventListener) {
element.removeEventListener(type, handler, false)
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler)
} else {
element["on" + type] = null
}
},

getEvent: function (event) {
//使用这个方法跨浏览器取得event对象
return event ? event : window.event
},

getTarget: function (event) {
//返回事件的实际目标
return event.target || event.srcElement
},

preventDefault: function (event) {
//阻止事件的默认行为
if (event.preventDefault) {
event.preventDefault()
} else {
event.returnValue = false
}
},

stopPropagation: function (event) {
//立即停止事件在DOM中的传播
//避免触发注册在document.body上面的事件处理程序
if (event.stopPropagation) {
event.stopPropagation()
} else {
event.cancelBubble = true
}
},

getRelatedTarget: function (event) {
//获取mouseover和mouseout相关元素
if (event.relatedTarget) {
return event.relatedTarget
} else if (event.toElement) {
//兼容IE8-
return event.toElement
} else if (event.formElement) {
return event.formElement
} else {
return null
}
},

getButton: function (event) {
//获取mousedown或mouseup按下或释放的按钮是鼠标中的哪一个
if (document.implementation.hasFeature("MouseEvents", "2.0")) {
return event.button
} else {
switch (
event.button //将IE模型下的button属性映射为DOM模型下的button属性
) {
case 0:
case 1:
case 3:
case 5:
case 7:
return 0 //按下的是鼠标主按钮
case 2:
case 6:
return 2 //按下的是中间的鼠标按钮
case 4:
return 1 //鼠标次按钮
}
}
},

getWheelDelta: function (event) {
//获取表示鼠标滚轮滚动方向的数值
if (event.wheelDelta) {
return event.wheelDelta
} else {
return -event.detail * 40
}
},

getCharCode: function (event) {
//以跨浏览器取得相同的字符编码,需在keypress事件中使用
if (typeof event.charCode == "number") {
return event.charCode
} else {
return event.keyCode
}
},
}

开始新一轮的学习

大晴天,白天上课,晚上班会。在傍晚时发现了有一丝的腰疼。晚上回到寝室突然又有点心绞痛的迹象···。
年纪轻轻应该不会有大碍,应该吧···毕竟也没有去检查过身体。
今天开始应该会把兼职辞了,开始新的学习吧。驾照什么的···就留着寒暑假有空再说吧。

date: 22:35 2018/10/30

基本用法

1
2
3
4
5
6
7
8
9
10
function* testGenerator() {
yield "hello"
yield "world"
return "done"
}
let test = testGenerator()
test.next() // { value : 'hello', done : false }
test.next() // { value : 'world', done : false }
test.next() // { value : 'done', done : true }
test.next() // { value : undefined, done : true }
Read more »

Iterator 概念

Iterator 是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构,只要部署 Iterator 接口,就可以完成遍历操作。
Iterator 的主要作用:为数据结构提供统一的、简便的访问接口;使得数据结构的成员能够按照某种次序排列;供 for…of 消费。
遍历过程如下:

  1. 创建一个指针对象,指向当前数据结构的起始位置。
  2. 第一次调用指针对象的 next 方法,将指针指向数据结构的第一个成员。
  3. 第二次调用 next 方法,指向第二个成员。
  4. 不断调用 next 方法,直到指针指向数据结构的结束位置。

每次调用 next 方法都会返回数据结构当前成员的信息,返回一个包含 value 的 done 两个属性的对象。value 属性是当前成员的值,done 属性是一个布尔值,表示遍历是否结束。
模拟 next 方法返回值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var it = makeIterator(['a', 'b'])
it.next() // { value : 'a', done : false }
it.next() // { value : 'b', done : false }
it.next() // { value : undefined, done : true }
function makeIterator(array) {
var nextIndex = 0
return {
next: function () {
return nextIndex < array.length
? { value: array[nextIndex++], done: false }
: { value: undefined, done: true }
},
}
}

遍历器与所遍历的数据结构实际上是分开的,完全可以写出没有对应数据结构的遍历器对象,或者用遍历器对象模拟出数据结构。无限运行的遍历器对象的例子:

1
2
3
4
5
6
7
8
9
10
11
12
var it = idMaker()
it.next().value // 0
it.next().value // 1
//...
function idMaker() {
var index = 0
return {
next: function () {
return { value: index++, done: false }
},
}
}
Read more »

Promise 的特点

  1. 对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Fulfilled(已成功)、Rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
  2. 一旦状态改变就不会再变,任何时候得到的都是这个结果。Promise 对象的状态改变只有两个可能:从 Pending 变为 Fulfilled,从 Pending 变为 Rejected。只要这两种情况发生,这时就成为 resolve。就算改变已经发生,再对 Promise 对象添加回调函数,也会立即得到这个结果。与 Event 完全不同,Event 一旦错过再监听是得不到结果的。

基本用法

1
2
3
4
5
6
7
8
9
var promise = new Promise(function (resolve, reject) {
//some code

if (/*异步操作成功*/) {
resolve(value);
} else {
reject(error);
}
})
Read more »

  1. 从 Reflect 对象上可以获得语言内部的方法
  2. 修改某些 Object 方法的返回结果,让其变得更合理。比如 Object.defineProperty 在无法定义属性时会抛出一个错误,而 Reflect.defineProperty 则会返回 false
  3. 让 Object 操作都变成函数行为。
  4. 只要是 Proxy 对象的方法,就能在 Reflect 对象上找到相应的方法,无论 Proxy 怎么修改默认行为,总可以在 Reflect 上获取默认行为

静态方法

  • Reflect.apply(target, thisArg, args)
    等同于 Function.prototype.apply.call(func, thisArg, args),用于绑定 this 对象后执行给定函数。

  • Reflect.construct(target, args)
    等同于 new target(…args),提供了一种不使用 new 来调用构造函数的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    function Greeting(name) {
    this.name = name
    }
    //new 的写法
    const instance = new Greeting("张三")

    //Reflect.construct 写法
    const instance = Reflect.construct(Greeting, ["张三"])
Read more »

Proxy 用于修改某些操作的默认行为,等同与在语言层面做出修改,属于一种 meta programming。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let obj = new Proxy(
{},
{
get: function (target, key, receiver) {
console.log(`getting ${key}`)
return Reflect.get(target, key, receiver)
},
set: function (target, key, receiver) {
console.log(`setting ${key}`)
return Reflect.set(target, key, receiver)
},
}
)
obj.count = 1
//setting count
obj.count
//getting count
Read more »

ES6 提供了 Map 数据结构,它类似对象,也是键值对的集合,但是‘键’的范围不限于字符串,各种类型的值(包括对象)都可以当做键。Map 结构是一种更完善的 Hash 结构实现。如果需要‘键值对’的数据结构,Map 比 Object 更合适。

1
2
3
4
let m = new Map()
const o = { p: "hello" }
m.set(o, "content")
m.get(o) //'content'

Map 也可以接受一个数组作为参数,该数组的成员是一个表示键值对的数组:

1
2
3
4
5
6
7
8
const map = new Map([
["name", "张三"],
["title", "test"],
])

map.size //2
map.has("name") //true
map.get("name") //'张三'

Map 构造函数接受数组作为参数,实际上执行的是下面的算法:

1
2
3
4
5
6
const item = [
["name", "张三"],
["title", "test"],
]
const map = new Map()
item.forEach(([key, valule]) => map.set(key, value))
Read more »