オブジェクト内で定義したコールバック関数でオブジェクトのプロパティを変更する方法

投稿者: Anonymous

MonacaクラウドでOnsenUI/AngularJSを使いアプリ制作の勉強中です。

ファイルを扱うAngularJSサービスオブジェクトを作っています。
フォルダのファイル一覧を取得するメソッドの中でFileSystemAPIを使うため
コールバック関数を使わなくてはならないのですが、その中でファイル一覧を格納するプロパティ(this.x)を書き換えようとすると以下のようなエラーが出ます(use strict)。

Error in Success callbackId: FileXXXXXXXXXX : TypeError: Attempted to assign to readonly property.

JavaScriptの仕様のようですが、コールバック関数内でプロパティを変更する
スマートな回避方法があればお教え頂けると幸いです。

再現する簡略化したコードを追記いたします。
実際にはエラー発生箇所でディレクトリの中身をプロパティに設定したいと考えております。

var obj = function() {
    'use strict';

    this.directory = '';

    this.changeDirectory = function(directory, returnFunction){
        this.directory = directory; //問題なし
        pstFileSystem.root.getDirectory(directory, {create: true, exclusive: false},
            function(dirEntry){
                this.directory = directory; //エラー
                returnFunction(dirEntry);
            }
        );
    };
};

window.onload = function() {
    'use strict';

    console.log('pageinit start!');
    var o = new obj;
    o.changeDirectory("/", function(dirEntry){console.log('directory is "' + o.directory + '"');});
};

解決

外側のスコープの this にアクセスする方法は、方法は3つあります。

ひとつめ。ローカル変数に外側のスコープの this を保管して、それを使う。

var self = this;
...
function(dirEntry){
  self.directory = directory;
  returnFunction(dirEntry);
}

ふたつめ。コールバック関数の this に外側のスコープの thisbind する。

function(dirEntry){
  this.directory = directory;
  returnFunction(dirEntry);
}.bind(this)

このようにすると、コールバック関数の this は外側のスコープの this と同じオブジェクトになります。(IE9以降で動作します)

みっつめ。 ES2015 (ES6) で追加された ArrowFunction を使う。

(dirEntry) => {
  this.directory = directory;
  returnFunction(dirEntry);
}

ArrowFunction では、this は外側のスコープのものがそのまま使われます。(Chrome, Edge, Firefox, Opera で動作します)

回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *