Typescript类方法作为sort回调丢失上下文 如何实现函数复用?
问题原因
你遇到的报错本质是类方法作为独立回调传入Array.sort时,丢失了类实例的this绑定。Array.sort执行回调时默认使用全局上下文(严格模式下为undefined),因此objectpinnedSortSample内部的this指向undefined,自然无法读取pinnedSortSample方法。
解决方案
下面提供几种可落地的实现方案,均可保留this上下文、实现排序逻辑复用:
方案1:调用时用箭头函数包裹(最灵活,无需修改类定义)
传入sort时用箭头函数包裹类方法,箭头函数会继承当前作用域的this(也就是类实例),无需修改原有方法定义:
interface A { num: number } class Example { sortTwoLists():boolean { // 用箭头函数包裹,绑定this let sortList1 = [4,5,3,1,2].sort((a, b) => this.pinnedSortSample(a, b)); let sortList2 = [{num:4} as A, {num:5} as A, {num:3} as A, {num:1} as A, {num:2} as A] .sort((a, b) => this.objectpinnedSortSample(a, b)) let numsOnly = sortList2.map((x) => x.num) return numsOnly.length === sortList1.length && numsOnly.every((value, index) => value === sortList1[index]) } pinnedSortSample(item1:number, item2:number) { let pins = [3,6] if (pins.includes(item1) && pins.includes(item2)) { return pins.indexOf(item1) - pins.indexOf(item2) } else if (pins.includes(item1)) { return -1; } else if (pins.includes(item2)) { return 1; } else { if (item1 < item2) {return -1} if (item1 > item2) {return 1} return 0; } } objectpinnedSortSample(item1: A, item2: A) { return this.pinnedSortSample(item1.num, item2.num); } } const x = new Example().sortTwoLists(); console.log(x); // 输出 true
方案2:将类方法定义为箭头函数属性(永久绑定实例this)
直接把类方法定义为箭头函数属性,该方法的this会永久绑定到类实例,后续直接传入sort即可:
class Example { sortTwoLists():boolean { // 直接传方法即可,无需额外处理 let sortList1 = [4,5,3,1,2].sort(this.pinnedSortSample); let sortList2 = [{num:4} as A, {num:5} as A, {num:3} as A, {num:1} as A, {num:2} as A] .sort(this.objectpinnedSortSample) // 其余逻辑不变 } // 定义为箭头函数属性,自动绑定this到实例 pinnedSortSample = (item1:number, item2:number) => { // 原有逻辑不变 } objectpinnedSortSample = (item1: A, item2: A) => { return this.pinnedSortSample(item1.num, item2.num); } }
方案3:高阶函数实现通用适配(进一步提升复用性)
如果需要适配更多类型的对象排序,可以封装通用的高阶排序函数,无需为每种对象单独写适配方法:
class Example { // 基础排序逻辑不变 private pinnedSortSample(item1:number, item2:number) { let pins = [3,6] if (pins.includes(item1) && pins.includes(item2)) { return pins.indexOf(item1) - pins.indexOf(item2) } else if (pins.includes(item1)) { return -1; } else if (pins.includes(item2)) { return 1; } else { return item1 - item2; } } // 通用排序器生成方法,传入取值函数即可适配任意类型 createPinnedSorter<T>(getValue: (item: T) => number): (a: T, b: T) => number { return (a, b) => this.pinnedSortSample(getValue(a), getValue(b)) } sortTwoLists():boolean { // 数字数组直接用基础方法 let sortList1 = [4,5,3,1,2].sort((a,b) => this.pinnedSortSample(a,b)); // 对象数组传入取值函数生成专属排序器 const sorterForA = this.createPinnedSorter<A>(item => item.num) let sortList2 = [{num:4} as A, {num:5} as A, {num:3} as A, {num:1} as A, {num:2} as A] .sort(sorterForA) let numsOnly = sortList2.map((x) => x.num) return numsOnly.length === sortList1.length && numsOnly.every((value, index) => value === sortList1[index]) } }
内容的提问来源于stack exchange,提问作者Ryan Deschamps
相关产品推荐
相关产品推荐

