Skip to content

补充二

答疑

泛型

深入理解 TypeScript

泛型

内存泄露

使用原型链和不适用原型链

  • 挂原型更优是看情况的,如果这个对象重复使用才看得出优势

    比如:多次 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

vueints配置1

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

封装接口请求方法

cnode/api

  • 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>

常备不懈,才能有备无患