coffeescript this(@)の使い方
解決済
回答 1
投稿
- 評価
- クリップ 0
- VIEW 2,789
お世話になります。
以下のようなcoffeesciptを作成したとします。
ここではテキストフィールド内でreturnキーを押した時に入力した値をアラートすることを望んでいます。
class @TestClass
constructor: () ->
@bind()
bind: () ->
# リターンキー(13)が押されたら名前をアラート
$('.name').on 'keyup', (e) ->
if e.which == 13
@alertName
alertName: () ->
name = $('.name').val()
alert(name)
$('.name').val('')
$ ->
window.testClass = new TestClass()
コンパイルし、HTMLに組み込んだのが以下になります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>TestClass</title>
<meta name="description" content="">
<meta name="keywords" content="">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script type="text/javascript">
this.TestClass = (function() {
function TestClass() {
this.bind();
}
TestClass.prototype.bind = function() {
return $('.name').on('keyup', function(e) {
if (e.which === 13) {
return this.alertName;
}
});
$('.name').on('keyup', this.alertName);
};
TestClass.prototype.alertName = function() {
var name;
name = $('.name').val();
console.log(name);
alert(name);
return $('.name').val('');
};
return TestClass;
})();
$(function() {
return window.testClass = new TestClass();
});
</script>
</head>
<body>
<main>
<h1>名前アラート</h1>
<form onSubmit="return false;" class="meassge-input">
<input type="text" class="name" placeholder="リターンキーで入力した名前をアラートします">
<button name="button" type="button" class="say">
SAY!
</button>
</form>
</main>
</body>
</html>
しかし、Enterを押しても動作しません。
bind関数の中身をreturn $('.name').on('keyup', this.alertName);
($('.name').on 'keyup', @alertName
)とすれば望んだ動作ではありませんが、@alertName
を期待通り呼べています。
となると、@alertName
が呼べていないということになりそうです。
@
は常にインスタンスを指すと思っていたのですが、そうではないのでしょうか?
リターンキー(13)が押されたら、インスタンス関数を発火させるにはどうすれば良いでしょうか?
よろしくお願いいたします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+3
修正点は2カ所です。
$('.name').on 'keyup', (e) =>
if e.which == 13
@alertName()
と、->
の部分を=>
に変えてみてください。期待通りに動くと思います。
そして、@alertName
を@alertName()
に変えるとうまく実行されます。
【たぶん、よくわかる解説!!!】
CoffeeScriptの@
はthis.
です。ただthis.
になるだけです。しかし、ここでの問題はJavaScriptにおけるthis
の扱いです。JavaScriptでのthis
は関数を呼び出したときのレシーバ(.の前の部分)になります。ですので、class内のメソッドでは通常this
はインスタンス自身です。ですが、関数の中で作られる関数(->
は関数を作ります)が実行されるときに、this
がそのままインスタンス自身とは限りません。特にon
のようなコールバックを引数にする場合、コールバックの関数が今のインスタンスから呼び出されるとは限らないため、this
がインスタンス自身を指す保証はありません。
どういうことかというと、(e) -> ...
の関数が呼び出されるとき、jQueryの要素がその関数を呼び出します。つまり、this
はもう違う何かになってしまっています。そう、this
はもうTestClassのインスタンスでは無いのです。これはJavaScriptの仕様です。CoffeeScriptが悪いわけではありません。
これはかなり面倒なものです。そこでCoffeeScriptは=>
を開発しました。=>
と->
の違いはthis
を束縛するかどうかです。どういうことかというと=>
で関数を作った場合、その関数がどこでどう呼び出されようが、this
つまり@
は関数を作った時のインスタンスになります。どうやってそうしているのかはJavaScriptに変換してみるとわかりますのでぜひ確認してください。
まとめ: on
とかのコールバックには=>
を使えば、だいたいうまくいく
蛇足: この便利な=>
ですが、ECMAScript 2015にパクられました。IE以外のブラウザあれば、素のJavaScriptでも使えるようになります。
【たぶん、よくわかる解説2!!!】
JavaScriptでは関数(メソッド)をオブジェクトとして扱う場合と、それを呼び出す(評価する)場合が厳密に区別されます。それは後ろに()
を付けるかどうかです。では、CoffeeScriptはどうかというと、引数がある場合のみ()
を省略しても良いとなっています。逆に引数無しで関数を呼び出す場合は必ず()
が必要です。
つまり、@alertName
はただの関数オブジェクトです。それが実行されるわけではありません。しかし、@alertName()
はその関数オブジェクトを引数無しで呼び出します。また、引数がある場合、たとえば、@alertName 0
とした場合は、@alertName(0)
として解釈されますので、同じく呼び出されます。
CoffeeScriptではこのように、関数を呼び出したい(評価したい)場合に、引数無しの場合のみ()の省略ができません。なお、new TestClass
のようにnew式におけては、JavaScriptと同様に()を省略することは可能ですが、これは例外的なものです。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.32%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/04/02 18:36
しかし、`->`を`=>`に変えても動作しません。以下にcodepenで動作確認を行ったものを貼らせていただきました。どこか間違っていますでしょうか?
<p data-height="268" data-theme-id="0" data-slug-hash="VaMQqa" data-default-tab="html" data-user="hirokishirai" class="codepen">See the Pen <a href="http://codepen.io/hirokishirai/pen/VaMQqa/">VaMQqa</a> by Hiroki Shirai (<a href="http://codepen.io/hirokishirai">@hirokishirai</a>) on <a href="http://codepen.io">CodePen</a>.</p>
<script async src="//assets.codepen.io/assets/embed/ei.js"></script>
2016/04/02 18:37
http://codepen.io/hirokishirai/pen/VaMQqa/
2016/04/02 18:55
2016/04/02 18:59
期待通り動作致しました。
詳しくありがとうございました。