函数作为“一等公民”
const compareNumber = (a: number, b: number) => a-b
// lambda 表达式, JavaScript/TypeScript:箭头函数
//const compareNumber = (a: number, b: number) => a-b
const compareNumber = function (a:number,b:number) {
return b-a
}
let a = [5,2,1,6,8,10,5,25,16,23,11]
a.sort(compareNumber)
let a = [5,2,1,6,8,10,5,25,16,23,11]
a.sort((a: number, b: number) => {
return a-b
})
console.log(a)
const emp1 = {
name: 'john',
salary: 8000,
increaseSalary: function (p: number) {
this.salary *= p
}
}
function compareNumber(a:number,b:number) {
return a-b
}
let a = [5,2,1,6,8,10,5,25,16,23,11]
a.sort(compareNumber)
function createComparer(p: {smallerFirst: boolean}){
if (p.smallerFirst) {
return (a: number, b: number) => a-b
} else {
return (a: number, b: number) => b-a
}
}
let a = [5,2,1,6,8,10,5,25,16,23,11]
a.sort(createComparer({smallerFirst: false}))
高阶函数
函数的参数可以是函数
函数的返回值可以是函数
以上两种都属于高阶函数
loggingComparer():函数的参数和返回值都是函数
function loggingComparer(comp: (a: number, b: number) => number){
return (a: number, b: number) => {
console.log('comparing', a, b)
return comp(a, b)
}
}
function createComparer(p: {smallerFirst: boolean}){
if (p.smallerFirst) {
return (a: number, b: number) => a-b
} else {
return (a: number, b: number) => b-a
}
}
let a = [5,2,1,6,8,10,5,25,16,23,11]
const comp = createComparer({smallerFirst: true})
a.sort(loggingComparer(comp))
闭包
使局部变量的生命周期延长
function loggingComparer(
logger: (a: number, b: number) => void,
comp: (a: number, b: number) => number) {
return (a: number, b: number) => {
logger(a,b)
return comp(a, b)
}
}
function createComparer(p: {smallerFirst: boolean}){
if (p.smallerFirst) {
return (a: number, b: number) => a-b
} else {
return (a: number, b: number) => b-a
}
}
function processArray(a: number[] ){
let compCount = 0
// logger:闭包
const logger = (a: number, b: number) => {
console.log('comparing', a, b)
compCount++ //自由变量
}
const comp = createComparer({smallerFirst: true})
a.sort(loggingComparer(logger, comp))
return compCount
}
let a = [5,2,1,6,8,10,5,25,16,23,11]
const compCount = processArray(a)
console.log(a,compCount)
部分应用函数
下例中isGoodNumber有两个参数,我们希望先用一个已知的goodFactor,使用这个goodFactor去判断我们收到的每个v
即我们现在只有一个参数goodFactor,我们想先将goodFactor传入函数,这样isGoodNumber就只有一个参数,此时只有一个参数的isGoodNumber就可以作为filterArray的参数f传入filterArray
解决方法:使用闭包将goodFactor放入函数体中
方法一(推荐使用):
function isGoodNumber(goodFactor: number, v: number){
return v % goodFactor === 0
}
function filterArray(a: number[], f: (v: number) => boolean) {
return a.filter(f)
}
const GOOD_FACTOR = 2
const a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(filterArray(a, (v) => isGoodNumber(GOOD_FACTOR, v)))
方法二(加深印象):
function isGoodNumber(goodFactor: number, v: number){
return v % goodFactor === 0
}
function filterArray(a: number[], f: (v: number) => boolean) {
return a.filter(f)
}
function partiallyApply(
f: (a: number, b: number) => boolean,
a: number) {
return (b: number) => f(a, b)
}
const GOOD_FACTOR = 2
const a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(filterArray(a, partiallyApply(isGoodNumber, GOOD_FACTOR)))
回调函数会引起 “callback hell” 问题,如下例只能通过嵌套的方法计算2+3+4,会导致多层嵌套
function add (a: number, b: number, callback: (res: number) => void): void{
setTimeout(()=>{
callback(a+b)
},2000)
}
add(2,3,res => {
console.log('2+3',res)
add(res,4,res2=>{
console.log('2+3+4',res2)
})
})
改写为promise,代码更加清晰
function add (a: number, b: number): Promise<number>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(a+b)
},2000)
})
}
add(2,3).then(res => {
console.log('2+3',res)
return add(res,4)
}).then(res => {
console.log('2+3+4',res)
return add(res,6)
}).then(res =>{
console.log('2+3+4+6',res)
})
同时等待多个Promise
function add (a: number, b: number): Promise<number>{
return new Promise((resolve,reject)=>{
if (b % 17 === 0){
reject(`bad number: ${b}`)
}
setTimeout(()=>{
resolve(a+b)
},2000)
})
}
function mul(a: number,b: number): Promise<number>{
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve(a*b)
}, 3000)
})
}
// (2+3)*(4+5)
Promise.all([add(2,3), add(4,5)]).then(res => {
const [a,b] = res
return mul(a,b)
}).then(res => {
console.log(res)
})
interface Employee {
name: string
salary: number
bonus?: number
}
const emp1: Employee = {
name: 'john',
salary: 8000,
}
const emp2: Employee = {
name: '张三',
salary: 10000,
bonus: 20000,
}
e.name?.first?.startsWith('AAA')
interface Employee {
name?: {
first?: string
last: string
}
salary: number
bonus?: number
}
function hasBadName(e: Employee){
// 如果e.name为undefined则整个表达式都为undefined
return e.name?.first?.startsWith('AAA')
}
e.name!.first!.startsWith('AAA')
function hasBadName(e: Employee){
// ! 程序不会报错,确保name/first一定有值,如果没有值后果自负
return e.name!.first!.startsWith('AAA')
}
interface Employee extends HasName{
salary: number
bonus?: number
}
interface HasName {
name?: {
first?: string
last: string
}
}
e: WxButton|WxImage
e只能调用他们共有的属性visibleinterface WxButton {
visible: boolean
enabled: boolean
onClick(): void
}
interface WxImage {
visible: boolean
src: string
width: number
height: number
}
function processElement(e: WxButton|WxImage) {
e.visible
}
e as WxButton
,得到的类型为WxButtonfunction processElement(e: WxButton|WxImage) {
if ((e as any).onClick) {
const btn = e as WxButton
btn.onClick()
} else {
const img = e as WxImage
console.log(img.src)
}
}
(e as WxButton).onClick !== undefined
:要想调用其他属性需要首先判断e的类型,这里不能使用typeof判断,因为在js中看不到自己定义的接口,需要通过判断e是否具有某个属性来判断它的类型。function processElement(e: WxButton|WxImage) {
if (isButton(e)) {
e.onClick()
} else {
console.log(e.src)
}
}
function isButton(e: WxButton|WxImage): e is WxButton {
return (e as WxButton).onClick !== undefined
}
class Employee {
name: string
salary: number
private bonus: number = 0
constructor(name: string, salary: number){
this.name = name
this.salary = salary
}
}
class Employee {
private bonus?: number
constructor(public name: string, public salary: number){
this.name = name
this.salary = salary
}
updateBonus() {
if (!this.bonus){
this.bonus = 20000
}
}
}
class Employee {
private allocatedBonus?: number
constructor(public name: string,public salary: number){
this.name = name
this.salary = salary
}
// getter/setter
set bonus(v: number){
this.allocatedBonus = v
}
get bonus(){
return this.allocatedBonus || 0
}
}
const emp1 = new Employee('john',8000)
emp1.bonus = 20000
console.log(emp1.bonus) // 20000
console.log(emp1)
// Employee: {
// "name": "john",
// "salary": 8000,
// "allocatedBonus": 20000
// }
class Employee {
private allocatedBonus?: number
constructor(public name: string,public salary: number){
this.name = name
this.salary = salary
}
// getter/setter
set bonus(v: number){
this.allocatedBonus = v
}
get bonus(){
return this.allocatedBonus || 0
}
}
class Manager extends Employee {
private reporters: Employee[]
constructor(name: string, salary: number) {
super(name, salary)
this.reporters = []
}
addReporter(e: Employee){
this.reporters.push(e)
}
}
interface Employee {
name: string
salary: number
bonus?: number
}
class EmplImpl implements Employee{
private allocatedBonus?: number
constructor(public name: string,public salary: number){
this.name = name
this.salary = salary
}
// getter/setter
set bonus(v: number){
this.allocatedBonus = v
}
get bonus(){
return this.allocatedBonus || 0
}
}
class Manager extends EmplImpl {
private reporters: EmplImpl[] = []
addReporter(e: EmplImpl){
this.reporters.push(e)
}
}
const empImpl = new EmplImpl('john', 8000)
const emp1: Employee = empImpl
// 定义接口
interface Service {
login(): void
getTrips(): string
getLic(): string
startTrip(): void
updateLic(lic: string): void
}
// 实现接口
class RPCService implements Service {
login(): void {
throw new Error("Method not implemented.")
}
getTrips(): string {
throw new Error("Method not implemented.")
}
getLic(): string {
throw new Error("Method not implemented.")
}
startTrip(): void {
throw new Error("Method not implemented.")
}
updateLic(lic: string): void {
throw new Error("Method not implemented.")
}
}
const page = {
service: new RPCService() as Service,
onLoginButtonClicked() {
//使用接口
this.service.login()
}
}
// 实现接口
class RPCService {
login(): void {
throw new Error("Method not implemented.")
}
getTrips(): string {
throw new Error("Method not implemented.")
}
getLic(): string {
throw new Error("Method not implemented.")
}
startTrip(): void {
throw new Error("Method not implemented.")
}
updateLic(lic: string): void {
throw new Error("Method not implemented.")
}
}
// 定义接口
interface LoginService {
login(): void
}
const page = {
service: new RPCService() as LoginService,
onLoginButtonClicked() {
//使用接口
this.service.login()
}
}
用来约束参数类型
const a: number[] = []
等价于const a: Array
class MyArray<T> {
date: T[] = []
add(t: T) {
this.date.push(t)
}
map<U>(f: (v: T) => U): U[] {
return this.date.map(f)
}
print() {
console.log(this.date)
}
}
const a = new MyArray<number>()
a.add(1)
a.add(2000)
a.add(30000)
//(method) MyArray.map(f: (v: number) => string): string[]
console.log(a.map(v => v.toExponential()))
interface HasWeight {
weight: number
}
class MyArray<T extends HasWeight> {
date: T[] = []
add(t: T) {
this.date.push(t)
}
map<U>(f: (v: T) => U): U[] {
return this.date.map(f)
}
print() {
console.log(this.date)
}
sortByWeight() {
this.date.sort((a, b) => a.weight - b.weight)
}
}
class WeightedNumber {
constructor(public weight: number) { }
}
const a = new MyArray<WeightedNumber>()
a.add(new WeightedNumber(10000))
a.add(new WeightedNumber(200))
a.add(new WeightedNumber(30000))
a.sortByWeight()
console.log(a)