功能
Flow和TypeScript都是用来做JavaScript类型检查的!
使用JavaScript进行编程时可能遇到的问题分析
javascript语言特征介绍:JavaScript是一种弱类型的,动态类型检查的语言
弱类型
在定义变量的时候,我们可以为变量赋值任何数据,变量的数据类型不是固定死的,这样的类型叫做弱类型
var a=10;
a="abc"
a=[]
a=function(){};
强类型
在声明变量的时候,一旦给变量赋值,那么变量的数据类型就已经确定,之后如果要给该变量赋值其他类型的数据,需要进行强制数据类型转换
int a=10;
a="10" //报错
动态类型和静态类型
动态类型和静态类型的核心区别:动态类型的类型检查会在代码运行的时候进行,而静态类型的类型检查则是在编译时进行
var obj={};
obj.forEach(function(v,i){
}) //js在运行时类型检查报错
int num=100;
num='abc' //java在编译时就报错了
动态类型和弱类型带来的问题
可能因为传参等问题导致最后的效果与期望的效果不一样
代码中的错误只能在代码运行的时候被发现。例如:代码在测试时问题没发现,到客户那里显露,体现了不稳定性.好处是灵活,但灵活性与风险性成正比
var num=123;
var num1=456;
/*函数接收两个参数,两个参数需要是数值类型的 返回值为两个参数的和*/
function sum(a,b){
return a+b;
}
console.log(sum(nun,num1)) // 579
console.log(sum("abc",1)) //abc1
//与期望的效果不一样
function greet(obj){
obj.sayHi()
}
var o={
name:'张学友'
}
greet(o) //只有在运行时报错obj.sayHello is not a function
静态类型带来的好处
Eary Detection of Errors
Easy Code Analysis
Improves Code Readability
Improved IDE Support
Promotes Dependable Refactoring
静态类型存在的问题
1.会增加代码量
2.需要花时间掌握类型
3.可能会降低开发效率
如何在JavaScript开发中使用静态类型
1.Flow FaceBook的开源技术
2.TypeScript 微软公司开发的语言
Flow的使用
FLOW IS A STATIC TYPE CHECKER FOR JAVASCRIPT
Flow的基本使用步骤
安装
shell
npm init -y
npm i flow-bin -D
//@flow
function square(n:number):number{
return n*n;
}
square("2"); //Error
在flow中如果想要为一个数据添加类型
1.通过注释的方式进行添加(不会改写js代码,代码在添加完类型之后仍然可以正常运行)
2.通过直接改写js代码结构(推荐),如果要正常运行,需要使用babel进行转码
var 变量:数据类型 =数据 ;
//@flow //需要给文件添加@flow标记,否则flow不会对文件进行类型检测
var a/*:number*/=10;
a='abc' //报错
//@flow
var a:number=10;
a="abc"; //报错
使用flow进行类型检查
0.在package.json文件中,scripts属性中添加flow命令
1.需要为flow创建一个配置文件 .flowconfig
npm run flow init
2.执行类型检查
npm run flow
Flow配合babel进行使用
如果要运行代码,在运行之前需要通过babel进行转码操作
1.安装babel以及presets
npm i babel-cli babel-preset-flow -D
2.配置package.json添加build命令调用babel
...json
{
"script"{
"build":"babel ./src -d ./dist"
}
}
3.执行build命令对文件进行转换
shell
npm run build
flow中的类型演示
//number类型可以赋值的内容为:数字、NaN、Infinity
let a:number=100;
let b:number=NaNl
let c:number=Infinity;
//string类型
//string类型可以赋值的内容为:字符串
let string:string="123";
//boolean 布尔值类型
//void javascript中的undefiend
//null js中的null
//Array 类型
//在声明数据为数组类型的时候,我们需要为数组指定元素的类型
let arr:Array<number>=[1,2,3,4]
//any 类型 任何类型都可以
let name:any=123;
name='123'
使用flow来避免过于复杂的错误处理逻辑
/*
*@param {*} arr 传递一个数组进来,数组中包含数字
*函数传递计算出数组中所有数字的和,进行返回
*/
//不适用flow
function sum(arr){
//检查函数调用时是否有参数传入
if(!arr){
throw new Error("此函数需要传递一个数组作为参数");
}
//检查函数调用时传入的参数是否为数组
if(!Array.isArray(arr)){
throw new Error('此函数需要传递一个数组作为参数')
}
//检查用户传递进来的参数数组,是否为数字数组中
if(!arr.every(v=>typeof v==='number')){
throw new Error('此函数需要传递一个数组作为参数,数组中的元素需要全部为数字')
}
let result=0;
arr.forEach(v=>{
result+=v;
})
}
sum([123]);
sum('abc')
//使用flow
//@flow
function sum(arr:Array<number>){
let result=0;
arr.forEach(v=>{
result+=v;
})
}
flow中的函数类型
//参数a是number类型,b是number类型,返回值也是number类型
function test(a:number,b:number):number{
return a+b;
}
flow中的Maybe类型
//Maybe类型相当于给数据添加了两个可能的类型 null 和undefined
//a 可以接受number 也可以接受undefined 也可以接受null类型
function test(a:?number){
a=a||0;
console.log(a)
}
test(10)
test()
flow中类型的或操作
let a:number|string=10;
a='123';
flow中的对象类型
function greet(obj:{sayHello:()=>void,name:string}){
obj.sayHello()
}
var o={
name:'张学友',
sayHello(){
console.log("Hello")
}
}
greet(o)
TypeScript的使用
是什么
TypeScript是微软公司开发的一款开源JavaScript超集语言!
JavaScript超集:当前任何JavaScript都是合法的TypeScript代码
TypeScript主要为JavaScript提供了类型系统和ES6语法的支持
Flow是一个类型检查工具,TypeScript是一种开发语言
TypeScript有自己的编译工具,我们写好的TypeScript代码最终会通过编译器编译成JavaScriot代码进行运行!
安装
TypeScript命令行工具的安装(TS编译器)
npm i typescript -g
安装好了之后,全局会提供一个tsc
命令给我们使用!
ts的配置文件
tsc init
target:指的就是将ts代码要转换成哪个版本的js代码 es5 es3
module:指的就是将ts代码转换成js代码之后,使用的模块化的标准是什么
outDir:指的就是将ts代码转换成js代码之后,js代码存放的文件夹路径
rootDir:指的就是要将哪个目录的ts代码进行转换,ts代码的存放路径
strict:是否要将ts代码转换为严格模式的js代码!
tsc -p ./tsconfig.json
ts中的数据类型
//number
let a:number=10;
let b:number=NaN;
let c:number=Infinity;
let d:number=0xA12;
let e:number=0b1010101;
let f:number=0o75;
//string
let str:string="这是一个字符串"
let str1:string='这是一个字符串'
let str2:string=`hello 这是一个模板字符串${a}`
//boolean
let flag:boolean=true;
//数组
//Array<数据类型>
let arr:Array<number>=[1,2,3,4]
//数据类型[]
let arr1:number[]=[1,2,3,4]
//元组(Tuple)
let arr2:[number,string]=[1,'a'];
arr[2]='a' //越界去访问数组元素 两个类型都可以
arr[2]=1
//void空值
let res:void=undefined
//undefined
let res:undefined=undefined
//null
let res1:null=null
//any 表示任意类型
let somevar:any=10;
somevar='abc';
somevar=[];
//never类型
//never类型一般用在不可能返回内容的函数的返回值类型设置
function test():never{
while(true){
}
}
//object
let o:object={}
let o1:object=[] //引用类型都可以用object
//对象类型
let q={name:string,age:number}={name:'张学友',age:18}
//enum:枚举类型
enum Gender{
male=1,
female=0,
unKnow=-1
}
let gender:Gender=Gender.male
//类型断言
let str:any="abc"
let leng:number=str.length
//ts中的类
class Person{
//ES6不同的是,TS中属性必须声明,需要制定类型
name:string
//声明好属性之后,属性必须赋值一个默认值或者在构造函数中进行初始化
age:number
constructor(name:number,age:number){
this.name=name;
this.age=age
}
sayHello(msg:string):void{
console.log(msg)
}
}
//ts中的类继承
class Animal{
age:number
constructor(age:number){
this.age=age
}
eat(){
console.log('吃个大鸡腿儿')
}
}
class Dog extends Animal{
type:string
constructor(type:string,age:number){
super(age)
this.type=type
}
//子类如果出现了和父类同名的方法,则会进行覆盖
//也就是调用的时候,调用的就是子类张总的方法了
eat(){
console.log("狗对象中的eat方法")
}
}
var dog=new Dog('哈士奇',18)
//ts中类成员的访问修饰符
//指的就是可以在类的成员前通过添加关键字来设置当前成员的访问权限
//public:公开的,默认 所有人都进行访问
//private:私有的,只能在当前类中进行访问
//protected:受保护的,只能在当前类或者子类中进行访问
enum Clolor{
red,yellow,blue
}
class Car{
//如果不加访问修饰符或者public
public color:Color,
constructor(){
this.color=Color.red
}
//加了private之后,当前成员就只能在当前类中使用了!
private run(){
}
//加了protected之后,当前成员就只能在当前类或者子类中使用了
protected loadPeople(){
}
}
let byd=new Car()
class Audi extends Car{
run(){
console.log(this.color)
}
}
let audi=new Audi()
console.log(Audi)
//ts中的只读属性和参数属性说明
class Cat{
//如果给属性添加了readonly修饰,则这个属性无法被赋值
//而且属性必须在声明的时候或者在构造函数中被赋值
readonly name:string
constructor(type:string){
this.name="加菲"
this.type=type
}
}
var cat=new Cat()
//ts中类成员的存取器
class People{
name:string=""
}
//ts中类成员的存取器
class People{
private _name:string=""
get name():string{
return this._name
}
set name(value:string){
//设置器中可以添加相关的校验逻辑
if(value.length<2||value.length>5){
throw new Error("名字不合法,不许使用!")
}
this._name=value
}
}
var p=new People();
p.name='dsa'
console.log(p.name)
//接口
//接口可以理解为一个约定 一个规范
//接口使用interface进行声明
interface AjaxOptions{
url:string,
//接口的可选属性:给属性加上?之后,这个属性就是可选的!
type?:string,
data?:object,
success(data:object):void
}
//options参数中,需要包含url type data success
function ajax(options:AjaxOptions){
}
ajax({
url:"http:www.baidu.com",
type:"get",
data:{},
success(data){
}
})
interface Point{
//接口中只读属性
readony x:number,
y:number,
//接口的额外属性检查
[propName:string]:any
}
let poi:Point={
x:10,
y:10,
z:100
}
//ts中的函数类型接口
interface SumInterFace{
(a:number,b:number):number
}
let sum:SumInterFace=function(a:number,b:number){
return a+b;
}
interface PersonInterFace{
name:string,
age:string,
eat():void
}
class XiaoMing implements PersonInterFace{
name:string='小明'
age:number=18;
eat(){
}
}
//数据访问层代码的
//mysql oracle mongobd
//dbinterface CRUD
//接口继承接口
//接口继承类
interface TwoDPoint{
x:number,
y:number
}
interface ThreeDPoint extends TwoPoint{
z:number
}