Javascriptのthisでコケた話
スコープの問題だろう.
初版
function(data)のthisはfunction(data)を指していて,コンストラクタのthisではない.
/** * TSVファイルのパース結果を持つクラス * @param {undefined} characterClass キャラクタクラス * @returns {undefined} */ function Tsv(characterClass) { this.filePath = TABLE_DIR + characterClass + TABLE_EXTENTION; $.ajax(this.filePath, { dataType: 'text', error: function(jqXHR, textStatus, errorThrown) { var message = "file not found: " + this.filePath; console.log(message, textStatus); }, success: function(data) { this.data = $.parse(data).results; }, async: false }); } Tsv.prototype = { /** * table要素として出力する * @returns {undefined} */ show: function() { var tableData = this.data; var table = $("<table />").appendTo($("div#showTable")); // table caption table.append($("<caption />", {"text": this.filePath})); // table header var thead = $("<thead />"); thead.appendTo(table); var tr = $("<tr />"); tr.appendTo(thead); this.data.fields.forEach(function(col) { tr.append($("<th />", {"text": col})); }); // table body this.data.rows.forEach(function(row) { var tr = $("<tr />"); tr.appendTo(table); this.data.fields.forEach(function(col) { tr.append($("<td />", {"text": row[col]})); }); }); } };
改訂
コンストラクタを変えた.function(data)中,ローカル変数tableDataで受けておいて,function(data)後,コンストラクタ終了直前にthis.dataへ代入する.show()でのthis.dataアクセスは3箇所あるが,初め2個が成立した.ただ,最後が良くなかった.コケた.
/** * TSVファイルのパース結果を持つクラス * @param {undefined} characterClass キャラクタクラス * @returns {undefined} */ function Tsv(characterClass) { this.filePath = TABLE_DIR + characterClass + TABLE_EXTENTION; var tableData; $.ajax(this.filePath, { dataType: 'text', error: function(jqXHR, textStatus, errorThrown) { var message = "file not found: " + this.filePath; console.log(message, textStatus); }, success: function(data) { tableData = $.parse(data).results; }, async: false }); this.data = tableData; }
第2訂
2重forEach内部のthis参照先が期待通りでない.ああ,そうか.初版と同様,funtion(row)で切り離されたんだ.show()にも手を加えた.先頭でtableDataに受けておいて,これを使用する.解決した.
Tsv.prototype = { /** * table要素として出力する * @returns {undefined} */ show: function() { var tableData = this.data; var table = $("<table />").appendTo($("div#showTable")); // table caption table.append($("<caption />", {"text": this.filePath})); // table header var thead = $("<thead />"); thead.appendTo(table); var tr = $("<tr />"); tr.appendTo(thead); tableData.fields.forEach(function(col) { tr.append($("<th />", {"text": col})); }); // table body tableData.rows.forEach(function(row) { var tr = $("<tr />"); tr.appendTo(table); tableData.fields.forEach(function(col) { tr.append($("<td />", {"text": row[col]})); }); }); } };