vue3源码是用typescript编写的,如果ts语法不熟悉看起来还是非常难过的。先来复习下ts相关知识。
typescript简介
- 以JavaScript为基础构建的语言
- 是JavaScript一个超集
- 可以在任何支持JavaScript的平台中执行
- 扩展了JavaScript并增加了类型
- 不能被JS解析器直接执行,需要先将TS编译为js
ts开发环境搭建
-
安装node
-
使用npm安装typescript
npm install -g typescript
-
创建一个ts,命令行进入文件目录使用
tsc xx.ts
进行编译,然后执行node xx.js
或者 安装ts-nodenpm install -g ts-node
, 执行 ts-node xx.ts
ts的类型声明
- 类型声明就是给变量设置了类型,使得变量
只能存储某种类型
的值 - 如果你的变量的
声明和赋值
是同时进行的,那么可以省略掉类型声明 - 常用的类型包括:
number、string、boolean、字面量、any、unknow、void、never、object、array、tuple、enum
例如:基础静态类型
const count: number = 123;
const myName:string = 'hi';
一般基础静态类型可以省略,因为ts可以自动推断识别。
对象静态类型:
const person: {
name: string,
age: number
} = {
name: 'hhh',
age: 18
}
const person:tring[] = ['arr', 'sss']
ts编译选项配置
增加tsconfig.json可以通过增加配置对代码进行编译
,如果项目根目录有配置文件,会使用配置文件的配置进行编译。
{
// 用来指定哪些ts文件需要被编译
// ** 表示任意目录 *表示任意文件
include:[
'./src/**/*
],
// 不需要编译的文件目录,默认值['node_modules']
exclude: [
'./src/hello/**/*'
],
// 只能文件
// files
// 编译的配置
"compilerOptions": {
// target 要编译的模板,默认es3,兼容性比较好,es3、es5、es6 es2015 es2016 es2017 es2018 es2019 es 2010
"target":"ES6" // 编译为es6
// module 指定模块化解决方案, none commonjs amd system umd es6 es2015 es2020 esnext
"module": "es2015" // 推荐es2015
// lib 项目中使用的库,有默认值默认不需要改
// "lib": ["dom"]
// outDir 编译后文件所在目录
"outDir": "./dist",
// 将代码合并为一个文件,所有的全局作用域代码合并为同一个文件
"outFile": "./dist/app.js"
// 是否对js进行编译
"allowJs": false,
// 是否检查js代码是否符合代码规范
"checkJs: false,
// 是否移除注释
"removeComments":true,
// 不生成编译后的文件
"noEmit": false,
// 当有错误时不生成编译文件
"noEmitOnError": true,
// 代码检查相关配置
// 所有严格检查总开关
"strict": true
// alwaysStrict 编译后的文件是否使用严格模式
"alwaysStrict": true,
// 不允许隐式any类型
"noImplictAny": true,
// 不允许不明确类型this
"noImplictThis": true,
// 严格的检查空值
"strictNullChecks": true
}
}
webpack打包ts代码
ts很少单独使用,一般要和打包工具例如webpack一起使用,从零搭建流程:
第一阶段
- 安装相关依赖:
npm init
npm i -d webpack webpack-cli typescript ts-loader
- 创建webpack.config.js
- 创建tsconfig.json
{
"compilerOptions": {
"module": "ES2015",
"target": "ES2015",
"strict": true
}
}
- 在package.json中增加build命令
- 执行npm run build 即可打包
第二阶段
- 自动生成html,并引入相关资源,需要引入html-webpack-plugin
npm i -d html-webpack-plugin
- 内置服务器,实现自动刷新
npm i -d webpack-dev-server
- 清空dist目录
npm i -d clean-webpack-plugin
- 增加reslove配置,用来指定引用模块
resolve: { extensions: ['.ts', '.js'] }
第三阶段
- 为了更好的兼容性,使用babel转换
npm i -D @babel/core @babel/preset-env babel-loader core-js
其中core-js是用来兼容语法的,例如promise在ie中没有,会自定义一个promise,配置useage会按需引入
webpack打包后会生成一个立即生成箭头函数,可以通过output的配置environment 不使用箭头函数和const语法
output: {
path: path.resolve(__dirname, 'dist'),
filename: "bundle.js",
// 兼容性配置
environment: {
arrowFunction: false,
const: false
}
},
-
识别less 安装
npm i -D less less-loader css-loader style-loader
-
样式兼容性处理
npm i -D postcss postcss-loader postcss-preset-env
通过以上安装,完整的webpakc.config.js如下:
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
// 引入清空文件插件
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
// webpack所有配置信息
module.exports = {
mode: 'production',
entry: "./src/index.ts",
output: {
path: path.resolve(__dirname, 'dist'),
filename: "bundle.js",
// 兼容性配置
environment: {
arrowFunction: false,
const: false
}
},
// 指定webpack打包时要使用的模块
module: {
// 指定要加载的规则
rules: [
{
test: /\.ts$/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
[
"@babel/preset-env",
{
targets: {
"chrome": "58",
"ie": "11"
},
"corejs": "3",
"useBuiltIns": "usage"
}
]
]
}
},
'ts-loader'
],
// 要排除的文件
exclude: /node_modules/
},
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
// 引入postcss
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
"postcss-preset-env",
{
browsers: 'last 2 version'
}
]
]
}
}
},
"less-loader"
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new htmlWebpackPlugin({
template: './src/index.html'
})
],
// 用来设置引用模块
resolve: {
extensions: ['.ts', '.js']
}
}
面向对象
一切操作都要通过对象来进行。对象包含两个部分: 属性
和方法
.
class Person {
// 定义属性
name:string = 'meng';
// 在属性前使用static,是类型属性
age: number = 18;
// 只能访问不能修改
readonly name: string = 'mmmm';
// 方法
sayHello() {
console.log('hello');
}
}
const per = new Person();
console.log(per.name)
构造函数
class Dog {
name:string;
age:number;
// 在类里面不能直接赋值,需要构造函数
constrctor(name:string, age:number) {
// this就是当前创建的那个对象
this.name = name;
this.age = age;
}
bark() {
// this表示当前调用方法的对象
console.log(this.name);
}
}
const dog = new Dog('小黑', 2);
dog.bark();
继承
class Animal {
name:string;
age:number;
// 构造函数会在对象创建时调用
constrctor(name:string, age:number) {
// this就是当前创建的那个对象
this.name = name;
this.age = age;
}
bark() {
// this表示当前调用方法的对象
console.log(this.name);
}
}
// Animal是父类,Dog为子类,拥有父类的所有属性和方法
// 子类可以继续添加方法和属性
class Dog extends Animal {
run() {
console.log(this.name)
}
// 如果定义和父类相同的方法,会覆盖父类(方法重写)
sayHello() {
console.log('wangwang)
}
}
class Cat extends Animal {
}
const dog = new Dog('wangcai', 4);
const cat = new Cat('mimi', 2);
super关键字
super就是当前类的父类,由于子类会覆盖父类的构造函数,可以通过super关键字来执行父类的构造函数。
class Father {
constructor(name:string) {
this.name = name;
}
sayHello() {
console.log('动物再叫');
}
}
class Child extends Father {
constructor(name: string,age: number) {
// 调用父类的构造函数
super(name);
this.age = age;
}
sayHello() {
super.sayHello();
}
}
抽象类
以abstract开头的类是抽象类,和其他类关系不大,只是不能用来创建对象;
抽象类是专门用来继承
的,抽象类可以添加抽象方法
abstract class Animal {
name:string;
constructor(name:string) {
this.name = name;
}
abstract sayHello():void;
}
class Cat extends Animal {
sayHello() {
console.log('cat miaomiao' )
}
}
接口
用来定义一个类的结构,应该包含哪些属性和方法
,也可以用类型声明去使用,可以重复使用,两者都用。
接口可以在定义类的时候去限制类的结构,只定义对象的方法,而不考虑实际值
在接口中所有的方法都是抽象方法
interface myinterface {
name: string;
age: number;
sayHell():void;
}
interface myinterface {
gender:string
}
// 定义类时,可以使类去实现一个接口,实现接口就是使类满足接口的要求
class MyClass implements myinterface {
name: string;
constructor(name:string) {
this.name = name;
}
sayHello( {
console.log('hi all')
})
}
属性封装
属性可以被任意修改,可能会导致数据不安全。
public
// 公共属性private
// 私有属性,只能类内部修改 可以定义get方法拿到内部的属性,通过set来修改
getter和setter可以作用属性的存储器 ts设置getter方法的方式
get name() {
// console.log('get 执行了')
return this._name;
}
set name(value:string) {
this._name = value;
}
protected
只能在当前类和当前的子类中使用
class A {
proteceted num:number;
constructor(num:number) {
this.num = num;
}
}
class B extends A {
test() {
console.log(this.name);
}
}
// 可以直接将属性定义在构造函数中
constructor(public name: string, public age:number){
this.name = name;
this.age = age;
}
泛型
在定义函数或类时,如果遇到类型不明确
就可以使用泛型
function fn<T>(a: T): T {
return a;
}
可以直接调用具有泛型的函数:
let result = fn(10) // 不指定,ts会自动对类型进行推测
let result1 = fn<string>('hello'); // 指定泛型
// 泛型可以同时指定多个
function fn2<T,K>(A:T, B:K):T {
return a
}
fn2<number, string>(124,'hekkk');
interface Inter {
length: number;
}
// 表示泛型T必须是Inter实现类(子类)
function fn3<T extends Inter>(a: T):number {
return a.length
}
// 字符串包含length属性
fn3('1212')