Jason's Blog

Jason学习和分享笔记的地方

0%

TypeScript学习笔记(一)(基础部分)

预言:为什么学习TypeScript?

2020都来了,TypeScript还不快学习一下

VUE3也使用了TS,现在三大框架都转为TypeScript,Node无力回天,Deno前景明朗,使用V8引擎解析TS。

TS遍地开花,大势所趋。2020肯定迟早都要学的,不如早点儿赶上潮流(😥其实不算早了)

它是javascript的超集,有静态类型检查,清晰函数参数,接口属性,增加了代码的可读性。

入门学习推荐:

TypeScript入门教程文档

技术胖ts视频教程

安装

TypeScript 的命令行工具安装全局:

1
cnpm install -g typescript

helloWorld

创建文件hello.ts

阅读全文 »

浏览器跨域问题

处于安全考虑 如果协议、域名或者端口有一个不同就是跨域,Ajax 请求会失败。

jsonp

利用<script>标签没有 跨域限制指向一个需要访问的地址并提供一个回调函数来接收数据。只限于 get 请求。

实现jsonp封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function jsonp(url, jsonpCallback, success) {
let script = document.createElement('script')
script.src = url
script.async = true
script.type = 'text/javascript'
// 约定一个callback字段名,来传递函数名,前端通过该函数来拿到数据
window[jsonpCallback] = function(data) {
success && success(data)
}
document.body.appendChild(script)
}

jsonp('http://xxx', 'callback', function(value) {
console.log(value)
})

cors

它允许浏览器向跨域服务器发出XMLHttpRequest请求,从而克服跨域问题,它需要浏览器和服务器的同时支持。

在服务端增加一些头部属性就行,客户端浏览器会自动添加origin字段

阅读全文 »

小程序云开发学习

朋友圈看到了迷渡大哥说当这次小程序云开发的评委。疫情这么严重,在家闲的慌,想参加一下这个黑客马拉松,刺激一下自己

开始创建

使用小程序开发者工具,创建新项目,点击云开发

image-20200202214400410

登陆

右击创建login函数

image-20200202215513556

上传图片

点击上传图片,在云开发控制台,可以看到

阅读全文 »

new 和 instanceof

new模拟实现

1
2
3
4
5
6
7
8
9
10
11
function myNew() {
// 创建一个空对象
let obj = {}
// 取第一个参数构造函数
let Con = [].shift.call(arguments)
// 把把新对象的原型链 链到 构造函数的原型对象
obj.__proto__ = Con.prototype
// 绑定this 实现继承 , obj可以访问到构造函数的属性
Con.apply(obj, arguments)
return obj
}

instanceof

instanceof 可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype

1
2
3
4
5
6
7
8
9
10
11
12
13
function myInstanceof(left, right) {
left = left.__proto__
while (true) {
// 到链的顶端 null 还没找到,就说明没有继承关系
if (left === null || left === undefined)
return false
// 右边的原型对象 等于左边的_PROTO_ 就说明是继承关系
if (right.prototype === left)
return true
// 原型链深入
left = left.__proto__
}
}
阅读全文 »

实现call,apply,bind函数

  • 如果第一个参数为null ,则指向window
  • 改变了 this 指向,让新的对象可以执行该函数,并能接受参数

复习this指向

this永远指向最后一个调用这个方法的对象

回顾隐式绑定

1
2
3
4
5
6
7
8
9
const obj = {
name:'Jason',
getName(){
console.log(this); //obj
console.log(this.name); //Jason
}
};
obj.getName();

记住这个用法,他们用这个实现

实现call,apply

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// (context) this指向的对象 (...args) 扩展运算 传入参数, (args)就是apply 
Function.prototype.myCall = function(context, ...args) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
// 改变this指向如果不传的话默认上下文为 window
context = context || window
args = args ? args : []
// 定义一个唯一值
const key = Symbol()
// 把这个函数的this 写到call 对象的一个属性里
context[key] = this
// 通过“对象.方法(参数)”,可以把this指向对象
const result = context[key](...args)
// 删除对象添加的方法
delete context[key]
return result
}

实现bind

阅读全文 »

实现promise A+

promiseA+规范,研究了两天,看了几篇解析文章,跟着敲出来的,要是凭空自己写估计水平还没到,下面有我的解释

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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// promise的三个状态,pending => resolved or => reject, 不可逆
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'

// 传递一个fn执行器,在try中执行
function MyPromise (executor) {
// 防止this变向
const that = this
// 设开始状态为pending
that.state = PENDING
// 用于保存 resolve 或者 reject 中传入参数的值
that.value = null
// 保存then中的回调
that.resolvedCallbacks = []
// 失败的回调
that.rejectedCallbacks = []

function resolve (value) {
// 判断传入的值是否为 Promise 类型
if (value instanceof MyPromise) {
return value.then(resolve, reject)
}
// 保证异步执行顺序
setTimeout(() => {
if (that.state === PENDING) {
// 改pending状态为 resolve
that.state = RESOLVED
// 将传入的值赋值给 value
that.value = value
// 遍历回调执行数组
that.resolvedCallbacks.forEach(fn => fn(that.value))
}
})
}

// 同resolve
function reject (value) {
setTimeout(() => {
if (that.state === PENDING) {
that.state = REJECTED
that.value = value
that.rejectedCallbacks.forEach(fn => fn(that.value))
}
})
}

try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}

// then方法
MyPromise.prototype.then = function (onFulfilled, onRejected) {
const that = this
let promise2
// 解决没有传值的问题,当参数不是函数类型时,需要创建一个函数赋值给对应的参数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected =
typeof onRejected === 'function'
? onRejected
: reason => {
throw reason
}
if (that.state === PENDING) {
// 返回一个新的 promise 对象
return (promise2 = new MyPromise((resolve, reject) => {
// 往回调数组中 push 函数
that.resolvedCallbacks.push(() => {
// 执行函数中可能 报错 ,try catch 捕获
try {
const x = onFulfilled(that.value)
resolutionProcedure(promise2, x, resolve, reject)
} catch (r) {
reject(r)
}
})

that.rejectedCallbacks.push(() => {
try {
const x = onRejected(that.value)
resolutionProcedure(promise2, x, resolve, reject)
} catch (r) {
reject(r)
}
})
}))
}
if (that.state === RESOLVED) {
// onFulfilled(that.value)
return (promise2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
//因为穿透值的缘故,在默认的跑出一个error后,不能再用下一个的reject来接受,只能通过try,catch
try {
const x = onFulfilled(that.value)
//递归 判断他们是否为promise对象
resolutionProcedure(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
})
}))
}
if (that.state === REJECTED) {
// onRejected(that.value)
return (promise2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
try {
const x = onRejected(that.value)
resolutionProcedure(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
})
}))
}
}

function resolutionProcedure (promise2, x, resolve, reject) {
// 避免循环引用
if (x === promise2) {
return reject(new TypeError('循环引用'))
}
// 不是null ,是 对象 或 函数
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
// called用于判断是否已经调用过函数
let called = false
try {
if (typeof x.then === 'function') {
// 参数 x 作为this指向
x.then.call(
x,
success => {
// 如果调用过 就直接返回了
if (called) return
called = true
// 递归调用 .then 中是否还有子 promise
resolutionProcedure(promise2, success, resolve, reject)
},
err => {
if (called) return
called = true
// 错误直接返回
reject(err)
}
)
} else {
resolve(x)
}
} catch (e) {
if (called) return
called = true
reject(e)
}
// 如果不是对象或函数将 x 传入resolve
} else {
resolve(x)
}
}
阅读全文 »

数组方法整理

要操作数据的时候,数组一堆方法把我搞混沌了,每次都要查一下资料,干脆整理一下

forEach()

forEach() 方法对数组的每个元素执行一次提供的函数。mdn

不会返回执行结果,返回的是undefined,也就是说,forEach()会修改原来的数组,中途不能用常规操作跳出循环,不支持链式操作,forEach之前可以链式

当数组中元素是类型,forEach不会改变数组;当是引用类型,则可以改变数组

map()

map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果mdn

map()方法会得到一个新的数组并返回。速度更快,必须要有return。


阅读全文 »

如何实现JS继承

JS是通过链式继承的,ES6的继承实际是语法糖。自己手动实现一下继承加深印象。

es6之前是不支持接口直接继承的,所以就需要手动实现继承

通过这个图先熟悉一下JS内部,constructor和prototype和实例的关系

image-20200115231115613

原型链继承

1
2
// 把父的实例化对象,赋值给 child的原型对象
Child.prototype = new Parent()

问题一: 当原型链中包含引用类型值的原型时,该引用类型值会被所有实例共享;

问题二: 在创建子类型(例如创建Child的实例)时,不能向父类型(例如Parent)的构造函数中传递参数.

构造函数继承

阅读全文 »

700元垃圾佬主机大升级

事情从我买了根16G内存开始,买了内存没地方用,干脆配一台机器好罗。正好家里电脑很卡,老古董,最终组装成一般网游,影音无压力的家用台式。

内存

京东双十二买的酷兽 当时199 16G 2666MHz 的内存,用了个199 -15 的全品类券 ,白菜价184到手,单面2G*8颗粒组成16G容量,镁光颗粒。

RAM2img

cpu

最终选定一代锐龙,R5-1400 四核-八线程 基础频率3.2GHz。便宜就完事,全新带散热器淘宝只要350左右,其实9月就到这价格了,已经没有降价空间了。为了追求更便宜,买了咸鱼二手,cpu这种东西用不坏的,所以二手也稳。这块cpu也能稳定超频。唯一缺陷就是没有核心显卡,还得另外配,没显卡还是建议速龙3000G(APU).

image-20200113114601686

主板

映泰tb350-etc,全新矿板,可装六张显卡,支持AM4处理器,7相供电,很稳定,矿难清库存还剩点,230入手。唯一的缺点就是,不支持MVME接口,只能装sata固态。

阅读全文 »

Javscript题目

错题记录,有些题目懵逼

哪个选项是不正确的?
1
2
3
4
5
6
7
8
const bird = {
size: "small"
};

const mouse = {
name: "Mickey",
small: true
};
  • A: mouse.bird.size
  • B: mouse[bird.size]
  • C: mouse[bird["size"]]
  • D: All of them are valid

答案: A

JavaScript中,所有对象键都是字符串(除了Symbol)。尽管有时我们可能不会给定字符串类型,但它们总是被转换为字符串。

JavaScript解释语句。当我们使用方括号表示法时,它会看到第一个左括号[,然后继续,直到找到右括号]。只有在那个时候,它才会对这个语句求值。

mouse [bird.size]:首先它会对bird.size求值,得到smallmouse [“small”]返回true

但是,使用点表示法,这不会发生。 mouse没有名为bird的键,这意味着mouse.birdundefined。然后,我们使用点符号来询问sizemouse.bird.size。由于mouse.birdundefined,我们实际上是在询问undefined.size。这是无效的,并将抛出Cannot read property "size" of undefined

阅读全文 »