补充二
答疑
泛型
内存泄露
- javascript常见的内存泄漏
- 堆内存只增不减,针对于 Vue 可能是响应式数据太多,可以减少响应式数据
Object.freeze
使用原型链和不适用原型链
挂原型更优是看情况的,如果这个对象重复使用才看得出优势
比如:多次 new,因为在内存指向的都是一个,不会存在重复创建的情况;如果写在函数里面,每次 new 都会创建对应新的函数内存空间
GC 机制
找到不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因为其开销比较大,所以垃圾回收会按照固定的时间间隔周期的执行
个人理解:
- JS 使用垃圾回收机制来自动管理内存,代码最终由 JS 引擎来完成执行,所以 回收也由不同的平台决定
- GC 回收内存。内存:存放在 堆栈空间的内存(引用类型存放的位置)
- 代码执行时会不断地向执行栈加入不同的执行上下文(函数调用)
- 某个执行上下文中的代码运行结束之后,原则上就会回收该上下文中所引用的堆内存空间(闭包例外)
- 当下执行 JS 的引擎不同,依据不同的算法又存在不同的回收时机,总体说,回收空间时就是 GC 工作时
GC 方式:
标记清除
一次性遍历不一定找到所有可达对象,对象之间存在相互引用或对象本身存在 "子引用"
引用计数
引用计数是完成这件事情的一种统计方法,引用计数发现某个变量引用为 0 之后认定是 "垃圾",GC 机制开始工作,回收它占用的空间
增量标记
标记清除 + 标记整理
增量标记可以看做是 V8 引擎本身最终采用的一种优化后的 GC 算法
增量标记工作过程中需要用到的就是标记清除,增量标记主要是对于时间调度的制定
复制算法的工作方式是在新生代对象回收时说明,就是讲内存一分为二,然后把 A 空间内容复制到 B 空间,然后将 A 空间的内容全部当垃圾回收
Vue 中配置 Typescript
两种情况:
- 全新项目:使用 Vue-cli 脚手架创建 Vue 项目
- 已有项目:添加 Vue 官方配置的 Typescript 适配插件
vue 创建全新项目:
bash
vue create vue-with-ts
vue 配置:
bash
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, TS, Router, Vuex, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Use history mode for router? (Requires proper server setup for index fallback in production) No
? Pick a linter / formatter config: Standard
? Pick additional lint features: Lint on save, Lint and fix on commit
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
Typescript 相关配置
package.json
src\shims-vue.d.ts
- Typescript 默认是不支持加载
.vue
的模块的,需要告诉编辑器,所有以.vue
结尾类型都是 Vue
tsx
declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
shims-tsx.d.ts
- 补充 JSX 类型声明
tsx
import Vue, { VNode } from 'vue'
declare global {
namespace JSX {
interface Element extends VNode {}
interface ElementClass extends Vue {}
interface IntrinsicElements {
[elem: string]: any
}
}
}
定义组件的方式
使用 Options API
- 组件仍然可以使用以前的定义方式(导出组件选项对象,或者使用
Vue.extend()
) - 但是当我们导出的是一个普通的对象,此时 Typescript 无法推断出对应的类型
- 至于 VSCode 可以推断出类型成员的原因是因为我们使用了 Vue 插件
- 这个插件明确知道我们这里导出的是一个 Vue 对象
- 所以我们必须用
Vue.extend()
方法确保 Typescript 能够有正常的类型推断
html
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
data() {
return {
count: 0,
}
},
methods: {
increment() {
this.count++
// this.count.substr()
},
},
})
</script>
使用 Class API
在 Typescript 下,Vue 的组件可以使用一个继承自 Vue 类型的子类表示,这种类型需要使用 Component 装饰器去装饰
- 装饰器函数接收的参数就是以前的组件选项对象(data、props、methods 之类)
html
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
const GreetingProps = Vue.extend({
props: {
name: String
}
})
@Component
export default class App extends Vue {
count = 0
increment() {
this.count++
},
get message(): string {
return 'Hello, ' + this.name
}
}
</script>
使用 Class API + vue-property-decorator
html
<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
@Prop(Number) readonly propA: number | undefined
@Prop({ default: 'default value' }) readonly propB!: string
@Prop([String, Boolean]) readonly propC: string | boolean | undefined
}
</script>
关于 Decorator 装饰器语法
Decorator 提案经过了大幅修改,目前还没有定案,不知道语法会不会再变。所以建议了解即可,不建议在生产环境使用
js
@decorator
class A {}
// 等同于
class A {}
A = decorator(A) || A
封装接口请求方法
api/index.ts
tsx
import axios from 'axios'
export interface Post {
id: string
author_id: string
title: string
content: string
}
export const getPosts = (): Promise<Post[]> => {
// axios 返回的是 Promise
return axios({
url: 'https://cnodejs.org/api/v1/topics',
method: 'GET',
}).then(res => {
return res.data.data
})
}
getPosts().then(data => {
console.log(data[0].author_id)
})
App.vue
使用Class API
html
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
import { getPosts, Post } from '@/api/index'
@Component
export default class App extends Vue {
posts: Post[] = []
async created() {
const posts = await getPosts()
this.posts = posts
}
}
</script>
App.vue
使用Options API
html
<script lang="ts">
import Vue from 'vue'
import { getPosts, Post } from '@/api/index'
export default Vue.extend({
data(): {
posts: Post[]
} {
return {
posts: [],
}
},
async created() {
const posts = await getPosts()
this.posts = posts
},
})
</script>