一文带你搞懂ArkTS的this

一文带你搞懂ArkTS的this

HarmonyOS
2024-06-11 20:49:40
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
depengli

this、this、this......各种this指向傻傻分不清?本文就带你搞清楚ArkTS中各类this的用法。首先我们先看一段代码:

@Entry 
@Component 
struct MyComponent { 
  @State private count: number = 0 
​ 
  increase() { 
    this.count++ 
  } 
​ 
  decrease() { 
    this.count-- 
  } 
​ 
  build() { 
    Column() { 
      Text(`count: ${this.count}`) 
        .fontSize(48) 
      MySubComponent({ 
        increase: this.increase, 
        decrease: this.decrease 
      }) 
    }.width('100%').height('100%') 
  } 
} 
​ 
@Component 
struct MySubComponent { 
  private increase: () => void 
  private decrease: () => void 
​ 
  build() { 
    Row() { 
      Button('INCR').onClick(() => { 
        this.increase() 
      }) 
      Button('DECR').onClick(() => { 
        this.decrease() 
      }) 
    } 
  } 
}

上述代码本来想通过传递事件回调来实现数据的双向流动(本例只是为了说明问题,实际建议使用@Link来实现数据双向流动)。但是运行上述代码会发现,无论是点击INCR还是DECR按钮,都不会触发界面的更新。

为什么会出现这种情况呢?因为上述代码涉及到一个很坑的知识点:

this指向问题

显示绑定

首先,我们知道在JavaScript中,可以通过call、apply和bind来指定实现体中的this指向。这一过程,我们称之为

显示绑定

function sayHi(age) { 
  console.log(`Hi, my name is ${this.name}. I am ${age} years old.`); 
} 
​ 
sayHi.call({ name: 'Jack' }, 7); 
​ 
sayHi.apply({ name: 'Jack' }, [7]); 
​ 
const sayHi2 = sayHi.bind({ name: 'Mike' }); 
​ 
sayHi2(8);

隐式绑定

但函数直接通过圆括号()进行调用执行,又会发生什么事情呢?用一段代码简单地说明一下:

const user = { 
  name: "Jack", 
  sayHi() { 
    console.log(`Hi, my name is ${this.name}`); 
  } 
}; 
​ 
// 位置1 
user.sayHi(); // 输出:Hi, my name is Jack 
​ 
// 位置2 
const sayHi = user.sayHi; 
sayHi(); // 输出:Hi, my name is undefined

是不是很疑惑,为什么位置1可以正常输出user.name,而位置2输出的就是undefined了?

这是因为上述代码在执行过程中,触发了this的隐形绑定:

  • 位置1的`user.sayHi()`:相当于`user.sayHi.call(user)`
  • 位置2的`sayHi()`:相当于`sayHi.call(undefined)`

这也就解释了为什么位置2位输出的name值是undefined了。

bind(this)解决this指向问题

@Entry 
@Component 
struct MyComponent { 
  @State private count: number = 0 
​ 
  increase() { 
    this.count++ 
  } 
​ 
  decrease() { 
    this.count-- 
  } 
​ 
  build() { 
    Column() { 
      Text(`count: ${this.count}`) 
        .fontSize(48) 
      MySubComponent({ 
        // 函数的执行上下文bind以后,后续无论怎么调用都是指向bind对象 
        increase: this.increase.bind(this), 
        decrease: this.decrease.bind(this) 
      }) 
    }.width('100%').height('100%') 
  } 
} 
​ 
@Component 
struct MySubComponent { 
  private increase: () => void 
  private decrease: () => void 
​ 
  build() { 
    Row() { 
      Button('INCR').onClick(() => { 
        this.increase() 
      }) 
      Button('DECR').onClick(() => { 
        this.decrease() 
      }) 
    } 
  } 
}

箭头函数解决this指向问题

bind(this)虽然可以解决问题,但是每次传递函数回调时都要bind一下,太麻烦了。而且每次bind都会产生一个新的函数,开销上也比较浪费。

所以,我们可以考虑利用箭头函数的特性(箭头函数体内的this对象,就是定义

该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。)来解决this指向问题。

@Entry 
@Component 
struct MyComponent { 
  @State private count: number = 
​ 
  // 使用箭头函数解决this指向问题 
  increase = () => { 
    this.count++ 
  } 
​ 
  // 使用箭头函数解决this指向问题 
  decrease = () => { 
    this.count-- 
  } 
​ 
  build() { 
    Column() { 
      Text(`count: ${this.count}`) 
        .fontSize(48) 
      MySubComponent({ 
        increase: this.increase, 
        decrease: this.decrease 
      }) 
    }.width('100%').height('100%') 
  } 
} 
​ 
@Component 
struct MySubComponent { 
  private increase: () => void 
  private decrease: () => void 
​ 
  build() { 
    Row() { 
      Button('INCR').onClick(() => { 
        this.increase() 
      }) 
      Button('DECR').onClick(() => { 
        this.decrease() 
      }) 
    } 
  } 
}

引申思考

@Entry 
@Component 
struct MyComponent { 
  @State private count: number = 0 
​ 
  increase() { 
    this.count++ 
  } 
​ 
  decrease() { 
    this.count-- 
  } 
​ 
  build() { 
    Column() { 
      Text(`count: ${this.count}`) 
        .fontSize(48) 
      Row() { 
        Button('INCR').onClick(this.increase) 
        Button('DECR').onClick(this.decrease) 
      } 
    }.width('100%').height('100%') 
  } 
}

执行上述代码,思考点击INCR或DECR按钮是否会触发界面更新?

不会,而且还会JS Crash!

click事件回调时触发隐式绑定,将事件回调函数中的this绑定成unedefined,而我们尝试去访问undefined上的属性,就会触发JS Crash。解决方式与前一个示例相同。

分享
微博
QQ
微信
回复
2024-06-12 22:40:00
相关问题
ArkUI中如何获取mp4帧图片?
4979浏览 • 1回复 待解决
HarmonyOS如何从麦克风录制mp3
415浏览 • 1回复 待解决
ArkTs怎么实现扫扫功能?
4226浏览 • 1回复 待解决
ArkTS如何实现个底部弹窗?
368浏览 • 1回复 待解决
arkTs如何获取视频第帧图片?
665浏览 • 2回复 待解决
el1与el2件是否有区别
475浏览 • 1回复 待解决
ArkTS中math库是哪个?
2653浏览 • 2回复 待解决
如何在Native侧构建ArkTS对象
1844浏览 • 1回复 待解决
audioPlayer.src怎设置media里面的mp3
2292浏览 • 1回复 待解决
谁能告知ArkTS相关知识点总结,
678浏览 • 1回复 待解决