最新的ECMAScript标准定义了8种数据类型:
1、基本数据类型
// 原始数据类型: Boolean;Null;Undefined;Number;BigInt;String;Symbol
let isDone: boolean = false
// es6 中 number还支持二进制和八进制
let age: number = 10
let binaryNumber: number = 0b1111
// 字符串类型,也可使用es6中的模板字符串
let firstName: string = 'wly'
let message: string = `hello, ${firstName}`
// undefinde 和 null 所有类型的子类型
let u: undefined = undefined
let n: null = null
// undefined类型可以赋值给number类型的变量[官方这么讲,但是我码出来就是报错,暂时还未知]
let num: number = undefined
// any类型
let notSure: any = 4
notSure = 'maybe a string'
notSure = false
notSure.myName // 在任意值上访问任何属性都是允许的
notSure.getName() // 也允许调用任何方法
2、数组Array和元组Tuple
// 数组
let arrOfNumbers: number[] = [1,2,3] //定义数字类型的数组
arrOfNumbers.push(4)
function test() {
console.log(arguments) //arguments 是一个对应于传递给函数的参数的类数组对象。
}
function func1(a, b, c) {
console.log(arguments[0]) // 1
console.log(arguments[1]) // 2
console.log(arguments[2]) // 3
}
func1(1, 2, 3)
// 元组Tuple 声明几个类型就能写几个,不能多写少些
let user: [string, number] = ['wly', 123]
user.push(12) //但是可以push,push的值只能是string、number-联合类型
3、interface接口
// 定义一个接口 IPerson
interface IPerson {
readonly id: number; //readonly只读属性
name: string;
age?: number; //?可选属性,这一项可有可无,否则不可多项和少项
}
// 定义一个变量viking, 他的类型是IPerson
let viking: IPerson = {
id: 1,
name: 'viking'
}
4、函数
// 约定输入,约定输出
function add(x: number, y: number): number {
return x + y
}
let result = add(1, 2)
// z是个可选参数
const add2 = (x: number, y: number, z?: number): number => {
if(typeof z === 'number') {
return x + y + z
} else {
return x + y
}
}
// 函数本身的类型,注意在函数类型里面返回类型是个箭头
const add3: (x: number, y: number, z?: number) => number = add2
// 接口里面返回类型是个冒号
interface ISum {
(x: number, y: number, z?:number): number
}
let add4: ISum = add2
5、类型推论、联合类型、类型断言、类型守卫
let str = 'str'
// union types-联合类型 中间用竖线来分割
let umberOrString: number | string
umberOrString = 1
umberOrString.toString() // 只能访问此联合类型里共有的属性或方法
// type assertions-类型断言 as作为关键字-当编辑器无法判断我的代码,但是本人很清楚,我把它成string,你也可以用string方法
function getLength(input: string | number): number {
const str = input as string
if(str.length) {
return str.length
} else {
const number = input as number
return number.toString().length
}
}
//type guard-类型守卫 在不同条件的分支里面,智能缩小范围,降低代码出错
function getLength2(input: string | number): number {
if(typeof input === 'string') {
return input.length
} else {
return input.toString().length
}
}
6、枚举
// 数字枚举 关键词enum, 我们定义了一系列得方向,这里得值,枚举成员会被赋值为从 0 开始递增的数字
enum Direction {
Up,
Down,
Left,
Right
}
console.log(Direction.Up) // 0
console.log(Direction[0]) // Up // 这个枚举还做了反向映射
enum Direction2 {
Up = 'up',
Down = 'down',
Left = 'left',
Right = 'right'
}
const value = 'up'
if(value === Direction2.Up) {
console.log('go up!!')
}
// 常量枚举
const enum Direction3 {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT'
}
const value3 = 'UP'
if(value3 === Direction3.Up) {
console.log("go up!!!")
}// An highlighted block
var foo = 'bar';
注意字符串枚举跟常量枚举最本质得区分就是js中,字符串枚举只会执行Direction3.Up,其余在Direction3得其他属性值都不会执行
7、泛型
function echo<T>(arg: T):T {
return arg
}
// const str: string = 'str'
// const result = echo(str)
const result1 = echo(123)
function swap<T, U>(tuple: [T, U]):[U, T] {
return [tuple[1], tuple[0]]
}
const result2 = swap(['string', 123])
// 约束泛型
function echoWithArr<T>(arg: T[]):T[] {
console.log(arg.length)
return arg
}
const arrs = echoWithArr([1, 2, 3])
interface IWithLength {
length: number
}
function echoWithArrLength<T extends IWithLength>(arg: T): T {
return arg
}
const str = echoWithArrLength('str')
const obj = echoWithArrLength({ length: 10, width: 10 })
const arr2 = echoWithArrLength([1, 2, 3])
echoWithArrLength(13) // number里面没有length属性,所以报错
// 类的公有类型(public)和私有类型(private)
class Queue<T> {
private data: T[] = [];
push(item: T) {
return this.data.push(item)
}
pop() {
return this.data.shift()
}
}
const queue = new Queue<number>()
queue.push(1)
const popedValue = queue.pop()
if(popedValue) {
console.log(popedValue.toFixed())
}
// 泛型和interface
interface KeyPair<T, U> {
key: T
value: U
}
let kp1: KeyPair<number, string> = {key: 1, value: 'string'}
let kp2: KeyPair<string, number> = {key: 'str', value: 2}
let arr: number[] = [1, 2, 3]
let arrTwo: Array<number> = [1, 2, 3]
8、类型别名 和 交叉类型
// 类型别名 和 交叉类型
import { type } from "os"
let sum: (x: number, y: number) => number
const result = sum(1, 2)
type PlustType = (x: number, y: number) => number
let sum2: PlustType
const result2 = sum2(2,3)
// 支持联合类型
type StringOrNumber = string | number
let result3: StringOrNumber = '123'
result3 = 123
const str: 'name' = 'name'
const number: 1 = 1
// 字符串字面量
type Direcions = 'Up' | 'Down' | 'Left' | 'Right'
let toWhere: Direcions = 'Left'
// 交叉类型
interface IName {
name: string
}
type IPerson = IName & {age: number}
let person: IPerson = {name: '123', age: 123}
9、声明文件
(1)axios.d.ts //注.d.ts固定写法
注:这两个文件需要同时在编辑器中打开,不然axio会报错
// 它里面没有任何的实际实现代码,只有类型声明
// 只有类型 - 比如 interface,funciton 或者 class 等等
// declare function axios(url: string): string
interface IAxios {
get: (url: string) => string;
post: (url: string, data: any) => string
}
declare const axios: IAxios // declare 声明类型
declaration-files.ts
// axios('test.url')
axios.get('url')
axios.post('url', {name: 'viking'})
(2) 引入第三方声明文件
npm i axios
declaration-files.ts
import axios from 'axios'
axios.get('ulr')
axios.post('url', {name: 'viking'})
(3)声明文件-小例子 计算器
//第一种
// caculator.d.ts
type IOperator = 'plus' | 'minus'
type ICalculator = (operator: IOperator, numbers: number[]) => number
declare const calculator: ICalculator
// declaration-files.ts
calculator('minus', [1,2])
// 第二种
// caculator.d.ts
type IOperator = 'plus' | 'minus'
interface ICalculator {
(operator: IOperator, numbers: number[]): number;
plus: (numbers: number[]) => number;
minus: (numbers: number[]) => number;
}
declare const calculator: ICalculator
export default calculator // 也可以使用es6
// declaration-files.ts
import calculator from './calculator'
calculator.minus([1,3])
将第二种的caculator.d.ts代码,挪到node_modules下的@types中创建文件夹caculator里面建立文件index.d.ts里面(作为模块来使用)
// declaration-files.ts
import calculator from 'calculator'
10、内置类型
const a: Array<number> = [1, 2, 3]
// 大家可以看到这个类型,不同的文件中有多处定义,但是它们都是 内部定义的一部分,然后根据不同的版本或者功能合并在了一起,一个interface 或者 类多次定义会合并在一起。这些文件一般都是以 lib 开头,以 d.ts 结尾,告诉大家,我是一个内置对象类型欧
const date: Date = new Date()
date.getTime()
const reg = /abc/
// 我们还可以使用一些 build in object,内置对象,比如 Math 与其他全局对象不同的是,Math 不是一个构造器。Math 的所有属性与方法都是静态的。
reg.test('abc')
Math.pow(2, 2)
// DOM 和 BOM 标准对象
// document 对象,返回的是一个 HTMLElement
let body: HTMLElement = document.body
// document 上面的query 方法,返回的是一个 nodeList 类型
let allList = document.querySelectorAll('li')
allList.keys()
//当然添加事件也是很重要的一部分,document 上面有 addEventListener 方法,注意这个回调函数,因为类型推断,这里面的 e 事件对象也自动获得了类型,这里是个 mouseEvent 类型,因为点击是一个鼠标事件,现在我们可以方便的使用 e 上面的方法和属性。
document.addEventListener('click', (e) => {
e.preventDefault()
})
interface IPerson {
name: string,
age: number
}
let viking: IPerson = { name: 'viking', age: 20 }
type IPartial = Partial<IPerson>
let viking2: IPartial = { name: 'viking'}
type IOmit = Omit<IPerson, 'name'> // IPerson name属性忽略掉
let viking3: IOmit = { age: 20 }
11、配置文件
{
"files": ["test.ts", "test2.d.ts"],
"compilerOptions": {
"outDir": "./output",
"module": "ESNext",
"target":"ES5",
"declaration": true
}
vue3
vue-cli
vue-ui 图形化界面创捷项目
vite脚手架 不同于vue-cli的创新
// vue 3.0推荐vscode种volar插件,注将原来vetur禁掉
// 查看项目下的eslint版本
在这里插入图片描述
vite:https://cn.vitejs.dev/
vscode中之前用的插件是vetur,vue3.0用的插件是volar
ref
// 注:ref定义变量读取的时候写法是 该变量名.value
<template>
<h1>{{ count }}</h1>
<button @click="increase">ddddd</button>
<h2>{{ double }}</h2>
</template>
<script lang="ts">
// ref 是一个函数,它接受一个参数,返回的是一个神奇的 响应式对象。我们初始化的这个0作为参数包裹到这个对象中去,在未来可以检测到改变并作出对应的响应
import { defineComponent, ref, computed } from 'vue';
export default defineComponent({
name: 'App',
setup() {
const count = ref(0)
const double = computed(() => {
return count.value * 2
})
const increase = () => {
count.value++
}
return {
count,
increase,
double
}
}
});
</script>
<style></style>
reactive、toRefs
使用ref还是reactive可以选择准则
(1)就像刚才的原生javascript的代码一样,像你平常写普通的js代码选择原始类型和对象类型一样来选择使用ref还是reactive
(2)所有场景使用reactive,但要记得使用toRefs保证reactive
对象属性保持响应性
<template>
<h1>{{ count }}</h1>
<button @click="increase">ddddd</button>
<h2>{{ double }}</h2>
</template>
<script lang="ts">
import { defineComponent, computed, reactive, toRefs } from 'vue';
interface DataProps {
count: number;
double: number;
increase: () => void
}
export default defineComponent({
name: 'App',
setup() {
const data: DataProps = reactive({
count: 0,
increase: () => {
data.count++
},
double: computed(() => data.count * 2)
})
const refData = toRefs(data)
return {
...refData
}
}
});
</script>
<style>
</style>
生命周期
vue 2.0 -> vue 3.0
beforeCreate -> use setup()
created -> use setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
errorCaptured -> onErrorCaptured
//调试 debugger钩子函数
onRenderTracked
onRenderTriggered
watch
// watch 简单应用
watch(data, () => {
document.title = 'update' + data.count
})
// watch的两个参数,代表新的值和旧的值
watch(refData.count, (newValue, oldValue) => {
console.log("oldValue=",oldValue)
console.log("newValue", newValue)
document.title = 'update' + data.count
})
// watch多个值,返回的也是多个值的数组
watch([greetings, data], (newValue, oldValue) => {
console.log("oldValue", oldValue)
console.log("newValue", newValue)
document.title = 'updated' + greetings.value + data.count
})
// 使用greetings的写法watch reactive 对象中的一项
watch([greetings, () => data.count], (newValue, oldValue) => {
console.log('oldValue', oldValue)
console.log("newValue", newValue)
document.title = 'updated' + greetings.value + data.count
})
hooks
vue3的hooks函数相当于vue2的mixin,不同在与hooks是函数
vue3的hooks函数可以提高代码的复用性,可以在不同组件中利用hooks函数
例:
1、在src目录下创建一个hooks文件夹
2、创建文件名.ts
useMousePosition.ts
import { ref, onMounted, onUnmounted} from 'vue'
function useMousePosition() {
const x = ref(0) // x绑定响应式数据
const y = ref(0)
const updateMouse = (e: MouseEvent) => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
document.addEventListener('click', updateMouse)
})
onUnmounted(() => {
document.removeEventListener('click', updateMouse)
})
return {x, y}
}
export default useMousePosition
在***.vue中
<template>
<div>
<h1>x{{x}}</h1>
<h1>y{{y}}</h1>
</div>
</template>
<script lang="ts">
import { defineComponent,ref, computed, reactive, toRefs, watch, onMounted, onUnmounted} from 'vue';
import useMousePostion from './hooks/useMousePosition'
export default defineComponent({
name: 'App',
setup() {
const { x, y } = useMousePostion()
return {
x,
y
}
}
});
</script>
reactive版本
import { reactive, toRefs, onMounted, onUnmounted } from 'vue'
interface UseMouse {
x: number,
y: number
}
function useMousePosition() {
const useMouse: UseMouse = reactive({
x: 0,
y: 0
})
const updateMouse = ((e: MouseEvent) => {
useMouse.x = e.pageX
useMouse.y = e.pageY
})
onMounted(() => {
document.addEventListener('click', updateMouse)
})
onUnmounted(() => {
document.removeEventListener('click', updateMouse)
})
return {
...toRefs(useMouse)
}
}
export default useMousePosition
一、相比普通script语法的优势
script setup>是在单文件组件(SFC)中使用组合式API的编译时语法糖。相比于普通的
二、基本语法
// 需要将setup attribute添加到