質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.49%

  • PHP

    20379questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • HTML

    9000questions

    HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

  • jQuery

    6720questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • WebSocket

    170questions

    WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。

WebsocketとRatchetのサンプルコードについて

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 585
退会済みユーザー

退会済みユーザー

Websocket及び、JQueryについての知識が乏しい者ですので、お恥ずかしい質問かもしれませんがお答えいただければ助かります。

<!DOCTYPE html>
<html lang="ja">
<meta charset="utf-8">
<title>Chat</title>
<style>
.container {
    width: 600px;
}
.box{
    overflow:hidden;
}
.left {
    background-color: #D3D3D3;
    padding: 20px;
    margin: 5px;
    width: 300px;
    float:left;
    border-radius:10px;
}
.right {
    background-color: #ADFF2F;
    padding: 20px;
    margin: 5px;
    width: 300px;
    float:right;
    border-radius:10px;
}
</style>
<script src="http://code.jquery.com/jquery-2.2.4.js"></script>
<script>
(function($){
  var settings = {}; //変数settingsを空で置く

  var methods = { //ここから変数methodに各methodを代入していく
    init : function( options ) {
      settings = $.extend({
        'uri'   : 'ws://localhost:8080', //URIとは名前または場所を識別する書き方のルールの総称(親玉)。
                                       //URLやURNは、URIで定められたルールに従って書かれたり使われたりする。
                                       //'key':'値'の関係
                                       //ここでは連想配列を作っているのと同じ。
        'conn'  : null,
        'message' : '#message',
        'display' : '#display'
      }, options);
      $(settings['message']).keypress( methods['checkEvent'] );
      //settingsにextendで代入されているmessageの値#messageにキーボード上に反応があった際に、method[checkEvent]を行う
      //input type text id="message"へのキーボードのアクセスがあった際にcheckEventが発動。
      $(this).chat('connect');
    },


    checkEvent : function ( event ) { //書き込み用のmethod。
      if (event && event.which == 13) {  //13?
        var message = $(settings['message']).val();
        //input type=text id="message"のval()を代入
        if (message && settings['conn']) {
          settings['conn'].send(message + '');
          //websocketに変数messageを挿入
          $(this).chat('drawText',message,'right');
          //drawTextでhtmlを精製、
          $(settings['message']).val('');
        }
      }
    },

    connect : function () {
      if (settings['conn'] == null) {
        settings['conn'] = new WebSocket(settings['uri']);
        settings['conn'].onopen = methods['onOpen'];
        settings['conn'].onmessage = methods['onMessage'];
        settings['conn'].onclose = methods['onClose'];
        settings['conn'].onerror = methods['onError'];
      }
    },

    onOpen : function ( event ) {
      $(this).chat('drawText','サーバに接続','left');
    },

    onMessage : function (event) {
      if (event && event.data) {
        $(this).chat('drawText',event.data,'left');
      }
    },

    onError : function(event) {
      $(this).chat('drawText','エラー発生!','left');
    },

    onClose : function(event) {
      $(this).chat('drawText','サーバと切断','left');
      settings['conn'] = null;
      setTimeout(methods['connect'], 1000);
    },

    drawText : function (message, align='left') {
      if ( align === 'left' ) {
        var inner = $('<div class="left"></div>').text(message);
      } else {
        var inner = $('<div class="right"></div>').text(message);
      }
      var box = $('<div class="box"></div>').html(inner);
      $('#chat').prepend(box);
    },
  }; // end of methods

  $.fn.chat = function( method ) {
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist' );
    }
  } // end of function
})( jQuery );

$(function() {
  $(this).chat({
    'uri':'ws://localhost:8080',
    'message' : '#message',
    'display' : '#chat'
  });
});
</script>
</head>
<body>
  <input type="text" id="message" size="50" />
  <div id="chat" class="container"></div>
</body>
</html>
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;

    require dirname(__DIR__) . '/vendor/autoload.php';

    $server = IoServer::factory(
       new HttpServer(
           new WsServer(
               new Chat()
           )
       ),
       8080
   );

   $server->run();

コメントアウトに関しては、一つ一つ整理するために記入しております。
間違い、勘違いなどありましたらご教授いただければ幸いです。
上記2つのファイルはRatchetのマニュアルをそのままコピーして貼り付けたものになります。
htmlファイルのscript内にある$.fn.chatというメソッドがあるのですが、処理の内容が全く理解できず、頭を抱えております。$.fn(JQueryプラグイン)がなぜ記入する必要があるのか?
またchatメソッドがどういう処理をこの場合行なっているのか?
かなり丸投げな質問であることは重々承知しております。
当然一つ一つバラして検索するなどし、理解しようと試みたのですが、やはりchatメソッドの動作が理解できませんでした。引き続き理解に努めるよう努力いたしますが、ヒントなどでも結構ですので皆様の御知恵をお貸しいただければ幸いです。
よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

$.fnはjQueryオブジェクト($(truthy)として返って来るもの)のプロトタイプです。
jQueryプラグインでなくても、サンプルコードなら使用して良いのではないでしょうか。

結論からいうと、この関数はあまり意味がありません。
意図を想像することはできるのですが、その機能を実現できていません。
以下説明です。

 説明

この$.fn.chatには二つの機能があります。

 第一の機能: 内部でのthisを保持したメソッド呼び出し

if ( methods[method] ) {
  return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
}


の部分がそれを行います。
使用している箇所は全て$(this).chat('...', ...)の形です。
この機能では、methods[1番目の引数(メソッド名)]という関数を自分のthisと自分に渡された2番め以降の引数(Array.prototype.slice.call( arguments, 1 ))で呼び出しています。

なぜこんなことをしているか、私はこのプログラムの著者でないのでわかりませんが、以下のような理由が考えられます。
Javascriptのthisは変わっていますが、このプログラムの構成では普通の動作が問題になります。
このプログラムは「アプリケーションのためにオブジェクトを作るほどではないがthisとして設定を取り回したい」という微妙な規模です。(少なくとも著者はそう思ったようです)
しかし、そうすると実行したい処理が取り回したいオブジェクトのメソッドでないという状況になります。
メソッドにせずにthisを保つにはFunction.prototype.apply(以下apply)を使いたくなります。そしてapplyを書きまくるとコードが散らかるのでその部分を関数にしたいと考えます。
ところが作った関数を普通に呼び出すとthisは変わってしまいます
thisを保つには、Function.prototype.applyを使うかメソッドにするかしかありません。堂々巡りです。
そこで、そのthisを保ちながらapplyする関数を持っておくクラスをjQueryに兼ねてもらうことにしたようです。

 第二の機能: 外部からのオプション指定の受け付け

else if ( typeof method === 'object' || ! method ) {
  return methods.init.apply( this, arguments );
}


の部分がそれを行います。
applyを使って引数とthisを投げています。

ここでもthisを保つようにしているようです。
現状ではthisを保っても意味はありませんが、コードを拡張していくうちに、どこかのdivの中にチャット画面を出すという機能を持たせることになるかもしれません。
その時に、$(対象の要素).chatで呼び出され、thisとして対象の要素必要が出てきます。
それを見越してこういう作りになっているのでしょう。

 おかしなところ

ある程度普通の話なので、この辺りまではわかっているかもしれません。
ところが、thisとしてjQueryオブジェクトを持って、それがチャット画面につながると考えると、このコードにはおかしなところがあります。
init, connect, drawTextは$.fn.chat越しで呼ばれていますが他はイベントハンドラとして呼び出されており、そのためにthisが変わってしまっています。
特に、onOpen,onMessage,onError,onCloseではWebsocketオブジェクトをjQueryに渡したオブジェクトが生成されており、このオブジェクトをjQueryオブジェクトとして使うと、関数によってはエラーが発生してしまいます。

おそらく途中で気が変わってthisを保つことをやめたのに、methods.なんとか()の形への書き換えをしなかったのでしょう。
つまり、この$.fn.chatには意味がありません。

実際、$.fn.chatを取り除いて以下のようにしても動作しました。

<!DOCTYPE html>
<html lang="ja">
<meta charset="utf-8">
<title>Chat</title>
<style>
.container {
    width: 600px;
}
.box{
    overflow:hidden;
}
.left {
    background-color: #D3D3D3;
    padding: 20px;
    margin: 5px;
    width: 300px;
    float:left;
}
.right {
    background-color: #ADFF2F;
    padding: 20px;
    margin: 5px;
    width: 300px;
    float:right;

}
</style>
<script src="http://code.jquery.com/jquery-2.2.4.js"></script>
<script>
(function($){
  var settings = {};

  var methods = {
    init : function( options ) {
      settings = $.extend({
        'uri'   : 'ws://localhost:8080',
        'conn'  : null,
        'message' : '#message',
        'display' : '#display'
      }, options);
      $(settings['message']).keypress( methods['checkEvent'] );
      methods.connect();
    },

    checkEvent : function ( event ) {
      if (event && event.which == 13) {
        var message = $(settings['message']).val();
        if (message && settings['conn']) {
          settings['conn'].send(message + '');
          methods.drawText(message,'right');
          $(settings['message']).val('');
        }
      }
    },

    connect : function () {
      if (settings['conn'] == null) {
        settings['conn'] = new WebSocket(settings['uri']);
        settings['conn'].onopen = methods['onOpen'];
        settings['conn'].onmessage = methods['onMessage'];
        settings['conn'].onclose = methods['onClose'];
        settings['conn'].onerror = methods['onError'];
      }
    },

    onOpen : function ( event ) {
      methods.drawText('サーバに接続','left');
    },

    onMessage : function (event) {
      if (event && event.data) {
        methods.drawText(event.data,'left');
      }
    },

    onError : function(event) {
      methods.drawText('エラー発生!','left');
    },

    onClose : function(event) {
      methods.drawText('サーバと切断','left');
      settings['conn'] = null;
      setTimeout(methods['connect'], 1000);
    },

    drawText : function (message, align='left') {
      if ( align === 'left' ) {
        var inner = $('<div class="left"></div>').text(message);
      } else {
        var inner = $('<div class="right"></div>').text(message);
      }
      var box = $('<div class="box"></div>').html(inner);
      $('#chat').prepend(box);
    },
  }; // end of methods

  $(function() {
    methods.init({
      'uri':'ws://localhost:8080',
      'message' : '#message',
      'display' : '#chat'
    });
  });
})( jQuery );

</script>
</head>
<body>
  <input type="text" id="message" size="50" />
  <div id="chat" class="container"></div>
</body>
</html>

 その他

var settings = {}; //変数settingsを空で置く


Objectであることをはっきりと意識した方が良いかもしれません。
Javascriptには空の文字列、NaN、null、undefined、空のArrayなど色々な「空っぽいもの」があります。
……というか、ここに値を足していくんじゃないんですね。型宣言かなにかなんでしょうか。

var methods = { //ここから変数methodに各methodを代入していく


正確には各メソッドの代入ではありません。これはオブジェクト初期化子です。
これを代入と呼ぶと以下のような問題があると思います。

  • setterなどの理解に影響をきたすかもしれない
  • 先に書いたものでも定義に使用できないということが理解しにくくなるかもしれない
if (event && event.which == 13) {  //13?


13はKeyboardEvent.whichの値としてEnterキーを表します。(参考

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/14 17:00

    遅くなり大変申し訳ありませんでした。

    オブジェクト初期化子という言葉を初めて目にしました。他にも自分が理解できていなかった部分をここまで詳しく解説していただき感謝しております。
    まだまだ自分の知識が足りないことを痛感しましたが、一つ一つ身につけていこうと思います。本当にありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • PHP

    20379questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • HTML

    9000questions

    HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

  • jQuery

    6720questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • WebSocket

    170questions

    WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。