TypeScript 2:调用类的方法,而不是对象

时间:2017-09-21 09:35:24

标签: angularjs class typescript ionic-framework

我找到了一个很棒的service用于在Ionic中录制音频。 但至少有一件事我不明白:

例如,在第25行:

this.MediaPlugin.startRecord();

问题:为什么要调用this.MediaPlugin.startRecord()而不是this.mediaPlugin.startRecord(),其中this.mediaPlugin是一个对象而MediaPlugin是一个类?

如果类使用this.MediaPlugin来执行操作,为什么它会在get方法中返回一个对象?

完整代码:

import { Injectable } from '@angular/core';
import { MediaPlugin } from 'ionic-native';

export enum AudioRecorderState {
    Ready,
    Recording,
    Recorded,
    Playing
}

@Injectable()
export class AudioRecorder {
  mediaPlugin: MediaPlugin = null;
  state: AudioRecorderState = AudioRecorderState.Ready;

  get MediaPlugin(): MediaPlugin {
    if (this.mediaPlugin == null) {
      this.mediaPlugin = new MediaPlugin('../Library/NoCloud/recording.wav');
    }

    return this.mediaPlugin;
  }

  startRecording() {
    this.MediaPlugin.startRecord();
    this.state = AudioRecorderState.Recording;
  }

  stopRecording() {
    this.MediaPlugin.stopRecord();
    this.state = AudioRecorderState.Recorded;
  }

  startPlayback() {
    this.MediaPlugin.play();
    this.state = AudioRecorderState.Playing;
  }

  stopPlayback() {
    this.MediaPlugin.stop();
    this.state = AudioRecorderState.Ready;
  }
}

3 个答案:

答案 0 :(得分:1)

this.MediaPlugin是对get的引用。使用这种语法,它将在第一次调用时构造MediaPlugin,但在后面的调用中使用构造。

(这个解决方案对我来说似乎有点奇怪,因为仅仅使用AudioRecorder类中的构造函数来初始化this.mediaPlugin更有意义,然后使用{{1其他地方)

答案 1 :(得分:0)

首先,以下方法是一个getter,我猜它是尝试使用延迟初始化实现readonly属性。

get MediaPlugin(): MediaPlugin {
    if (this.mediaPlugin == null) {
        this.mediaPlugin = new MediaPlugin('../Library/NoCloud/recording.wav');
    }

    return this.mediaPlugin;
}

因此,当您第一次尝试访问this.MediaPlugin时,正在创建MediaPlugin的新实例。当您实例化AudioRecorder并且不使用它时(由于某些原因)它可以帮助您节省内存而不是立即创建MediaPlugin实例。 (见Lazy loading pattern

回答你的问题:

  

为什么要调用this.MediaPlugin.startRecord()而不是   this.mediaPlugin.startRecord()其中this.mediaPlugin是一个对象和   MediaPlugin是一个类?

Typescript不提供任何常见的延迟加载机制,实现它的方法是使用getter方法创建私有属性(如在AudioRecorder类中)。

调用this.MediaPlugin.startRecord(),你可以封装MediaPlugin实例的创建和操作逻辑。

答案 2 :(得分:0)

命名约定

有人对命名约定搞砸了。该属性的名称应为mediaPlugin,而不是MediaPlugin

名为MediaPlugin的属性访问者的原因是,已存在名为mediaPlugin的支持字段。

有些人认为应该将支持字段称为_mediaPlugin。其他人则认为这会违反命名惯例。如果是后者,可以称之为mediaPluginField

class AudioRecorder {
  mediaPluginField: MediaPlugin = null;

  get mediaPlugin(): MediaPlugin {
    if (this.mediaPluginField === null) {
      this.mediaPluginField = new MediaPlugin('../Library/NoCloud/recording.wav');
    }

    return this.mediaPluginField;
  }
}

依赖性反转

然而,正如@Vladyslav Yefremov所指出的,可以说更好的选择是通过构造函数注入MediaPlugin依赖项,或者从某种服务定位器中提取它。

class AudioRecorder {
  constructor(private mediaPlugin: MediaPlugin) { }
}

class AudioRecorder {
    private mediaPlugin: MediaPlugin;

    constructor(mediaPlugin: MediaPlugin) {
        this.mediaPlugin = mediaPlugin;
    }
}

懒惰实例化

我没有立即看到需要懒惰地实例化媒体插件,因为录音机需要一个媒体插件来执行所有操作。

然而,可能是因为媒体插件在实例化时具有加载媒体文件的副作用。如果是这种情况,则媒体插件属性会被懒惰地实例化,以延迟资源的打开,直到实际需要它为止,即需要AudioRecorder时。