跳到主要内容

TypeScript

· 阅读需 3 分钟
Yana Ching
Front End Engineer

语言类型

静态类型:编译阶段确定变量类型 (C++)

  1. 类型检查极度严格
  2. 立即发现错误
  3. 运行时性能好
  4. 自文档化

动态类型:执行阶段确定变量类型(JS)

  1. 类型检查宽松
  2. bug 可能隐藏数月甚至数年
  3. 运行时性能差
  4. 可读性差

动态类型语言支持者:

性能可以改善(V8)、语言的灵活性更加重要

隐藏的错误可通过单元测试发现

文档可以通过工具生成

image-20230914110045849

TS基本使用

## 全局安装 typescript
npm install typescript -g

即可在全局使用 tsc 命令

## 初始化 tsconfig.json 文件
tsc --init

## 编译指定文件
tsc <path/to/your/js/file>
e.g. tsc ./src/index.js

数据类型

ES6

  1. Boolean
  2. Number
  3. String
  4. Array
  5. Function
  6. Object
  7. Symbol
  8. undefined
  9. null

Typescript 数据类型

在 ES6 基础上补充了

  1. void
  2. any
  3. never
  4. 元组 限定数组个数和数组类型
  5. 枚举
  6. 高级类型

类型注解 (变量/函数) : type

# 基础类型
let bool:boolean = true
let str: string = 'str'
let num: number = 123

# 数组
let arr: number[] = [1, 2, 3]
# 使用范型和联合类型
let arr2: Array<number | string> = [1, 2, 3, '4']

# 元组:特殊数组
let temp:[string, number] = ['1', 2] // 否则报错
temp.push(2) // 越界,可插入,但是访问不了该元素

# 函数
let add = (x: number, y: number) => x + y
let compute = (x:number, y:number) => number
let compute = (a, b)=> a + b

# 对象
let obj: {x: number, y: number} = {x:1, y:2}


# symbol 没有相同元素
let s1: symbol = Symbol()
let s2 = Symbol()
console.log(s1 === s2 || s1 == s2) // false

# 枚举
# 数字枚举
enum Roles = {
Reporter = 1, // 默认是0,但是可指定数字,后面的元素自动递增
Developer,
Maintainer,
Owner,
Guest
}
Roles.Reporter // 1
## 字符串枚举
enum Answer = {
N: 'failed',
Y: 'succeed'
}
## 枚举成员
enum Char {
a,
b = Char.a,
c = 1 + 2;
d = Math.random(),
e = '123'.length
}

# 常量枚举: 编译阶段会被移除,减少无用代码
const enum Month {
Jan, Feb,
}
let month = [Month.Jan, Month.Feb] // 编译时将常量枚举替换成对应的常量

AJAX 动态加载

· 阅读需 5 分钟
Yana Ching
Front End Engineer

前情

Web 程序最初的目的是:共享数据(信息)

以前通过以下几种方式对服务端发起请求,获得服务端的数据:

  • 地址栏输入地址,回车,刷新
  • 特定元素的 href 或 src 属性
  • 表单提交
通过以上获取数据必须刷新网页,开销大 :::

AJAX ( Asynchronous JavaScript and XML )

通过 JavaScript 发送请求、接收响应,不必刷新页面获取最新数据

  • AJAX 就是浏览器提供的一套 API ,可以通过 JS 调用,从而实现控制请求与响应
  • XML 是描述数据的一种手段,现今常用 JSON 来描述,因为 XML 相比 JSON 冗余太多了

AJAX 基本使用

  1. 创建 XMLHttpRequest 类型的对象
  2. 设置请求行,与服务端特定端口创建连接 open函数
  3. 设置请求头 setRequestHeader( )
    • 使用什么格式的请求体就要设置相应的 Content-Type 告知服务器端
  4. 设置请求体 send( )
var xhr = new XMLHttpRequest()
console.log(xhr.readyState)
// => 0 初始化 请求代理对象

xhr.open(method, url, boolean)
console.log(xhr.readyState)
// => 1 open 已经调用,建立一个与服务端特定端口的连接(已经建立)
xhr.send()
xhr.addEventListener('readystatechange', function () {
switch (this.readyState) {
case 2:
console.log(this.readyState)
// => 2 已经接收到响应报文的响应头
break
case 3:
console.log(this.readyState)
// => 3 正在下载响应报文的响应体
// 可能为空 也可能不完整 在此处处理响应体不保险 (不可靠)
break
case 4:
console.log(this.readyState)
// => 4 一切OK
// 整个报文已经下载下来了
break
}
})

readyState 有五种状态,四个阶段(0~1、...)

  • 0 => 初始化,请求代理对象 new XMLHttpRequest()
  • 1 => 建立连接(已经建立) open
  • 2 => 已经接收到响应报文的响应头 send 之后
  • 3 => 正在下载响应报文的响应体
  • 4 => 整个报文已经下载下来了
应当设置请求体相应的 Content-Type 告知服务器 :::
  • onreadystatechange 函数只在状态改变的时候才响应,因此,如果 xhr.send(method, url, async) 中第三个参数 async 异步为 false 时,可能会出现来不及的现象
/**
* 同步与异步模式的区别在于
* 同步模式下 send 方法会出现等待的情况
*/
console.time('async')
var xhrAsync = new XMLHttpRequest() // 创建 xhr 对象
xhrAsync.open('GET', './time.php', 'true') // 与服务端创建连接
xhrAsync.send() // 设置请求体格式
console.timeEnd('async')
// async: 0.645751953125ms

console.time('sync')
var xhrSync = new XMLHttpRequest()
xhrSync.open('GET', './time.php', 'false')
xhrSync.send()
console.timeEnd('sync')
// sync: 0.340087890625ms

线程与进程

  • 进程:进行中的程序
  • 线程:CPU 的最小执行单元

总结

  • AJAX是浏览器提供的API

  • XMLHttpRequest 类型

  • onreadystatechange 事件 :只在状态改变的时候响应

  • readyState

    • 0:请求未初始化
    • 1:服务器连接已建立
    • 2:请求已接收(响应头)
    • 3:请求处理中(有可能拿到也有可能拿不到)
    • 4:请求已完成,且响应已就绪
ValueStateDescription
0UNSENTClient has been created. open() not called yet.
1OPENEDopen() has been called.
2HEADERS_RECEIVEDsend() has been called, and headers and status are available.
3LOADINGDownloading; responseText holds partial data.
4DONEThe operation is complete.

2:headerreceive 接收到响应头

JS 原生创建对象

· 阅读需 1 分钟
Yana Ching
Front End Engineer

一些概念

  • 封装:把属性和方法封装在对象中
  • 对象:具体值某个事物,有特征(属性)和行为(方法)

创建对象的三种方式

系统构造函数

var obj=new Object();

字面值

var obj={};

自定义构造函数(优化后的工厂模式)

    //自定义构造函数
function Person(name,age,gender){
this.name=name;
this.age=age;
this.gender=gender;
this.work=function(){
console.log(this.name+"is working");
}
}
var per3=new Person("wang",50,"male");
per3.work();
console.log(per3.work);
console.log(per3 instanceof Person);//可以判断类型

工厂模式(推论)

      //工厂模式
function createObject(name,age,gender){
var obj=new Object();
obj.name=name;
obj.age=age;
obj.gender=gender;
obj.sleep=function(){
console.log(this.name+" is sleeping");
};
return obj;
}
var per4=createObject("July",18,"female");
per4.sleep();

原型与继承

· 阅读需 4 分钟
Yana Ching
Front End Engineer

原型

  • 构造函数中为prototype,程序员使用
  • 实例对象中为__proto__,浏览器使用,不是很标准
  • 实例对象中的__proto__指向该实例对象的构造函数中的prototype
  • 构造函数中的prototype属性和方法,可通过实例对象调用
  • 当系统内置对象的属性或者方法无法满足需求的时候,可以通过原型为内置对象添加属性或者方法
String.prototype.ffff = function(){};

简单的原型写法

Per.prototype={
//缺少构造器,需要手动指向构造函数
constructor:Person
}

继承

通过原型实现,改变原型的指向

借用构造函数继承的时候,不能继承方法

//自调用函数
(function () {
function Person(name, age, sex, weight){
this.name = name;
this.age = age;
this.sex = sex;
this.weight = weight;
}
Person.prototype.hello = function(){
console.log("Hello!My name is "+this.name+" This is my message: age:"+this.age+" sex:"+this.sex+" weight:"+this.weight);
}
window.Person = Person;
}());
//test
var per1 = new Person("Ming", 15, "female", "45kg");
per1.hello();

//自调用函数
((function(){

//----START--------
function Student(score, name, age, sex, weight){
Person.call(this, name, age, sex, weight);//=======借用构造函数==========
this.score = score;
}
//--------END-------------


Student.prototype.myScore = function(){
console.log(this.name+"======"+this.age+"============="+this.sex+"==========="+this.weight+"============"+this.score);
}
window.Student = Student;
// Student.prototype.hello = function(){
// console.log("Student's hello");
// }
})());
//test
var stu1 = new Student(94,"Li",45,"male","95kg");
console.log(stu1.myScore);//输出代码内容
stu1.myScore();
stu1.hello();//=========报错(该方法无法实现方法的共享)
运行结果

1571208798824

组合继承

借用构造函数继承属性,同时改变原型的指向,可以解决属性和方法的继承问题

//自调用函数
(function () {
function Person(name,age,sex,weight){
this.name=name;
this.age=age;
this.sex=sex;
this.weight=weight;
}
Person.prototype.hello=function(){
console.log("Hello!My name is "+this.name+" This is my message: age:"+this.age+" sex:"+this.sex+" weight:"+this.weight);
}
window.Person=Person;
}());
//test
var per1=new Person("Ming",15,"female","45kg");
per1.hello();

//自调用函数
((function(){
function Student(score,name,age,sex,weight){
Person.call(this,name,age,sex,weight);//=================借用构造函数
this.score=score;
}
//-------------------START---------------------
Student.prototype=new Person();//不传值,改变原型的指向
//-------------------end---------------------
Student.prototype.myScore=function(){
console.log(this.name+"======"+this.age+"============="+this.sex+"==========="+this.weight+"============"+this.score);
}
window.Student=Student;
})());
//test
var stu1=new Student(94,"Li",45,"male","95kg");
console.log(stu1.myScore);//输出代码内容
stu1.myScore();
// console.log(stu1);/////////////////==================不改变指向的时候__proto__指向Student构造函数原型
// stu1.hello();//=========报错(该方法无法实现方法的共享)
console.log(stu1);/////////////////==================改变指向的时候__proto__指向Person构造函数原型
stu1.hello();//实现方法共享
运行结果

1571210145954

拷贝继承(直接传址,非拷贝)

即把对象中原型的所有属性和方法使用遍历的方式复制一份给另一个对象

方式一

var obj1={
name:"MIMI",
age:20,
sleep:function(){
console.log("sleeping");
}
};
var obj2=obj1;//栈中=====传址
console.log(obj2.name,obj2.age);
obj2.sleep();

方式二

var obj1={
name:"MIMI",
age:20,
sleep:function(){
console.log("sleeping");
}
};
var obj2={};//栈中=====传址
for(var key in obj1){
obj2[key]=obj1[key];//JS是动态类型的语言,书写键值对相当于与"."出了属性
}
console.log(obj2);

浅拷贝

在堆中实现原型属性和方法的拷贝,原对象中的仍然存在部分不可拷贝的方法和属性
    ((function(){
function Person(){

}
Person.prototype.age=10;
Person.prototype.sex="male";
Person.prototype.weight="50kg";
Person.prototype.play=function(){
console.log("Have a good time!");
}
window.Person=Person;
})());
var obj2={};
for(var key in Person.prototype){
obj2[key]=Person.prototype[key];
}
console.dir(obj2);
obj2.play();

运行结果

1571233114884