ラベル javascript の投稿を表示しています。 すべての投稿を表示
ラベル javascript の投稿を表示しています。 すべての投稿を表示

2015年12月9日水曜日

bower + grunt + yo ⇒ yeoman によるWEBアプリのひな形作成


bower、grunt、yoを導入し、WEBアプリケーションのひな形をyeoman(ヨーマン)で作成するところまでの手順を残しておく。



◆ bower
bowerフロントエンドライブラリ、例えばAngularJSなどの依存性の管理ツールである。

(bowerのインストール)
$ sudo npm install -g bower

(初期化)
アプリケーションのルートディレクトリへ移動しておく。
$ mkdir myapp

$ cd myapp

$ bower init
bower.json
が作られる。

(bowerで管理させるモジュールのインストール)
この後利用するangularモジュールをインストールする。
saveオプションを付けているので、設定ファイルbower.jsonに追記される。
$ bower install angular --save

ここへ保存される。
$ ls bower_components/
npmのnode_modulesに相当するフォルダである。

アプリから使う場合はこう指定する。
<script src="bower_components/angular/angular.min.js"></script>



◆ grunt
JavaScript用のビルドツールである。

(grunt操作用のコマンドラインツールのインストール)
grunt本体ではない(cli: Common Language Infrastructure)。
$ sudo npm install -g grunt-cli

(package.jsonの作成)
gruntをインストールする前に、nodejs用のパッケージを管理するpackage.jsonを作成しておく。
rubyでいうところのgemfileである。
$ npm init
package.json
が作られる。

(grunt本体とプラグインのインストール)
grunt本体とコードの圧縮を担当するプラグインなどをインストールしてみる。
gruntで使うプラグインもpackage.jsonで管理したいため、save系オプションを付与する。
--save:     アプリそのものの実行で利用するパッケージ
--save-dev: アプリ開発で利用するパッケージ

package.json内の下の違いである。
"dependencies": {}
"devDependencies": {}

grunt関係は--save-devを指定すると理解しておけば良い。
$ npm install grunt grunt-contrib-cssmin grunt-autoprefixer grunt-contrib-uglify grunt-contrib-imagemin grunt-contrib-watch -save-dev
インストールしたプラグインはこの配下で管理される。
node_modules


このディレクトリを削除しても依存関係を読み取りインストールしなおしてくれる。
$ node install

(Gruntfile.jsファイルの作成)
$ vi Gruntfile.js
この中で記載していけばよい。



yo, yeoman
yeomanはフレームワークに対応したアプリケーションのひな形を作成するyoを中心に、grunt、bowerといったソフトウェアから構成されるツールセットである。
gruntとBowerはすでに使用できる。ひな型生成ツールであるyoをインストールし、yeomanを使ってアプリのひな型を生成する。

(gemのアップデート)
まずgemを先にアップデートしておく。
$ sudo gem update --system

compassも利用するので入れておく。
$ sudo gem install compass

(yeomanのインストール)
$ sudo npm install -g yo

今回はAngularJSを使うことを想定する。またその雛形を作成するためのジェネレータもインストールする。
$ sudo npm install -g generator-angular

(ひな形の作成)
$ yo angular


(アプリケーションの起動)
gruntサーバを起動する。
※オプションは"Gruntfile.js"内を参照のこと。
$ grunt serve

アクセスできるはずである。
http://localhost:XXXX/



2014年11月2日日曜日

Ajaxを使ったPOSTメソッドによるHTTP通信

◆ 目的
Ajaxの非同期通信を使ったPOSTメソッドによるHTTP通信を実現する。
今更な感があるが、jQueryなどのライブラリを利用する機会が多くなったため、
少しレイヤを下げて、改めて、JavaScriptとDOM(Document Object Model)の
コードを組み合わせた簡易なWEBアプリケーションを構築したくなったしだい。



◆ 動作概要
クライアントが入力フォーム(nameとage)を入力しsendボタンを押すと、
サーバへ非同期にPOST通信を発生させる。
サーバ側がフォームの内容をCGIで処理して実行結果をクライアントへ返答。
サーバからの応答はHTMLコード下段の部分に挿入する。
ページが遷移しないところがポイントである。



◆ HTMLコード
※サーバ設定がないため(CGIが実行できないので)、動作はしない

POST TEST

sample

send form

name:
age:




returning data

name: -
age: -


(実HTML)
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>POST TEST</title>
<link href="post.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="post.js"></script>
</head>
<body>
<h1>POST TEST</h1>
<p>sample</p>
<hr />
<h2>send form</h2>
<form action="post.rb" id="sendForm">
  <div>
    name:
    <input type="text" id="name" name="name" size="30" autocomplete="off" />
  </div>
  <div>
    age:
    <input type="text" id="age" name="age" size="3" autocomplete="off" />
  </div>
  <div>
    <input type="button" name="sendBtn" id="sendBtn" value=“send” />
  <div>
</form>
<hr />
<h2>returning data</h2>
<div>name: <span id="responseName">-</span></div>
<div>age: <span id="responseAge">-</span></div>
</body>
</html>



◆ CGIコード 
#!/usr/bin/ruby
require "cgi"
cgi = CGI.new

name = cgi["name"]
age = cgi['age']

response  = "name\t#{name}\n"
response += "age\t#{age}\n"

puts cgi.header
#puts "Content-Type: text/plain; charset=utf-8";
print "\n"
print response



◆ JavaScriptコード
簡単なコードなので説明は省略。
一部利用しない関数を断りを入れて書いているが、
これはただの自分用メモである。

var httpObj;
var timerId;
var timeoutSec = 10;

function printResData(textData) {
  var i;
  var lines = textData.split("¥n");
  var responseName = document.getElementById('responseName');
  var responseAge  = document.getElementById('responseAge');

  for(i = 0; i < lines.length; i ++) {
    var parts = lines[i].split("¥t");
    var name = parts[0];
    var value = parts[1];
    if(name == 'name') {
        responseName.childNodes[0].nodeValue = value;
    } else if(name == 'age') {
        responseAge.childNodes[0].nodeValue = value;
    }
  }

  document.getElementById('sendBtn').disabled = false;
}


function postData(e) {
  document.getElementById('sendBtn').disabled = true;

  var name = document.getElementById('name').value;
  var age  = document.getElementById('age').value;

  var postData;
  postData = 'name=' + encodeURIComponent(name) +
              '&age=' + encodeURIComponent(age);

  var targetUrl = 'post.rb';

  httpPostRequest(targetUrl, postData, printResData);
}


function httpPostRequest(targetUrl, postData, funcitonReference) {
  try {
    if(window.XMLHttpRequest) {
        httpObj = new XMLHttpRequest();
    } else {
        httpObj = false;
    }
  } catch(e) {
      httpObj = false;
  }
  if(! httpObj) {
    fail();
  }

  timerId = setInterval('timeoutCheck()', 1000);

  httpObj.open("POST", targetUrl, true);
  httpObj.onreadystatechange = function() {
    if (httpObj.readyState == 4) {
      clearInterval(timerId);
      if (httpObj.status == 200) {
        funcitonReference(httpObj.responseText);
      } else {
        alert(httpObj.status + ' : ' + httpObj.statusText);
        return false;
      }
    }
  }
  httpObj.send(postData);
}


function fail() {
  alert("error: your browser is not supported");
  return false;
}


function timeoutCheck() {
  timeoutSec --;
  if(timeoutSec <= 0) {
    clearInterval(timerId);
    httpObj.abort();
    alert('error: timeout');
    return false;
  }
}


function setListeners(e) {
  var sendBtn = document.getElementById('sendBtn');
   // true: capturing(from top), false: bubbling(from bottom)
  addListener(sendBtn, 'click', postData, false);
}


function addListener(elem, eventType, func, cap) {
  if(elem.addEventListener) {
    elem.addEventListener(eventType, func, cap);
  } else {
    fail();
    return false;
  }
}


/* 以下はここでは使わない
function removeListener(elem, eventType, func, cap) {
  elem.removeEventListener(eventType, func, cap);
}


function getElemPos(elem) {
  var obj = new Object();
  obj.x = elem.offsetLeft;
  obj.y = elem.offsetTop;
  while(elem.offsetParent) {
    elem = elem.offsetParent;
    obj.x += elem.offsetLeft;
    obj.y += elem.offsetTop;
  }
  return obj;
}

function getTargetNode(e) {
  var targetNode = e.target;
  return targetNode;
}

function stopDefaultAction(e) {
  e.preventDefault();
}


function stopPropagation(e) {
  e.stopPropagation();
}
*/


addListener(window, 'load', setListeners, false);

2013年7月16日火曜日

JavaScriptの言語仕様の理解



◆ 目的
JavaScriptでコンストラクタを用意し、そこからオブジェクト(インスタンス)を作り、プロトタイプチェーンをたどる様子を模式図を使って理解する。

少々厄介なオブジェクト、プロトタイプの関連が目が覚めたように分かるはずである。



◆ サンプルコード
・Personコンストラクタ関数Person()の作成

コンストラクタ関数は共通の性質はふるまいをもったオブジェクトを作る型である。
他の言語で言うところのクラスのようなものは、JavaScriptではただの関数で定義できるということである。

new演算子とともに記述されることを想定してカスタムコンストラクタ関数を生成する際には、通常の関数との混同を避けるために関数の最初の文字を大文字にするのがよいだろう。

var Person = function(age, gender) {
this.age = age;

this.gender = gender;

this.getAge = function() {
return this.age;
};

this.getGender = function() {
return this.gender;
};
};


・プロトタイププロパティに新しいオブジェクトの設定
Person.prototype.birthday = 'yyyymmdd';


・オブジェクト(インスタンス)化
person = new Person(20, 'man') 


コンストラクタ関数と言ってもただの関数のようなものなのだが、new演算子を使って呼ばれた場合にただの関数とは異にする特徴を示す。コンストラクタ関数はreturnがなくともよい。オブジェクトインスタンスを構築して返す。

JavaScriptではパラーメタに引数を渡さなくてもかまわない。引数が渡されなければその変数はUndefinedが設定される。



◆ 模式図
・サンプルコードの模式化
                       
Function.prototype   Object.prototypeへ
        ↑                  ↑
プロトタイプチェーン(__proto__ 経由)

Person()             Person.prototype
+---------------+    +----------------------+
| __proto__     |    | __proto__            |
| prototype     |    | constructor          |
| age           |    | birthday: 'yyyymmdd' |
| gender        |    |                      |
| getAge        |    |                      |
| getGender     |    |                      |
+---------------+    +----------------------+

 インスタンス化               ↑
      ↓              プロトタイプチェーン

     person
      +----------------------+
      | __proto__ *         |
      | age: 20              |
      | gender : 'man'       |
      | getAge: -            |
      | getGender: -         |
      +----------------------+

*
自分自身に存在しないプロパティ・メソッドが呼び出されると、__proto__ ([[Prototype]])をめぐった先を参照する。
person.__proto__ === Person.prototype

つまり、参照である。では、prototypeプロパティとしてbirthdayを設定したが、これはクラス変数のように、newされたオブジェクトで共有されるのだろうか。
person1 = new Person(〜);
person2 = new Person(〜);

person1.birthday = 19910101
person2.birthday = 20010101

alert(person1.birthday) // ?

答えは共有されない。person1.birthdayは19910101と表示される。代入時には、person1にbirthdayというプロパティが新たに作られ、そこに設定が代入されるためである。


(参考)
https://www.matthieuveillon.com/class/



2010年7月23日金曜日

closureとは何か

closureとは何か。javascriptを使って説明する。


◆ クロージャの特徴
(1) クロージャは変数に代入可能であり(つまり値であり)、
それを使用して関数の呼び出しができる。

(2) クロージャはそれが生成された箇所のローカル変数を参照できる。


具体的に上記を説明する前にサンプルコードを示す。
 1: <script>
   
 2:   var outer=function() {
 3:     this.x = 1;
     
 4:     this.inner= function() { // closure
 5:       this.x = this.x + 1;
 6:     };
 7:   }
     
 8:   var o = new outer();
     
 9:   // outer関数から変数xを参照
10:   alert(o.x); // 1
     
11:   // innter関数を呼び出し
12:   o.inner();
     
13:   // outer関数から変数xを参照
14:   alert(o.x); // 2
     
15:   // innter関数を呼び出し
16:   o.inner();
     
17:   // outer関数から変数xを参照
18:   alert(o.x); // 3
     
19: </script>



まずは特徴(1)から。
innerという変数に代入し(4行目)、その後、その変数経由で関数を呼び出している(12、16行目)。
ただ、これを実現するだけなら、Cであれば関数ポインタを使えばいい。

しかし(2)はできない。
サンプルコード内で変数xが複数の関数呼び出しをまたがり保持されている。
ここがクロージャをクロージャ足らしめている点である。

まとめると・・・
関数ポインタのような使い方ができるが、クロージャが生成された
箇所の変数も保持できる、これがクロージャである。



◆ 実装方法
どのように実装されるのかを説明する。
ローカル変数の領域は、関数に入った時点でスタック上に確保され、
抜けるときに解放されるのだが、この確保/解放されるひとかたまりのメモリをフレームと呼ぶ。
関数が呼び出された時に、その中で定義された変数と値を格納しておく場所である。

さて、サンプルコードに戻っていただきたい。
どこでフレームが作られるか。
outer内で1つのフレーム、そして
inner内でもう1つのフレーム、の合計2つである。
今回はinner内で新しい変数は出していないが、ここでyなどを定義すれば、
inner内のフレームに保持されるわけだ。

クロージャの特徴として、(2)があった。
再掲する。
"クロージャはそれが生成された箇所のローカル変数を参照できる。"

つまり、クロージャはouterとinnerの複数のフレームを保持しなければならない。

ではどうやって複数のフレームを保持するのか。
スコープチェーンを使えばいい。フレームを連結して管理するためのものだ。



◆ 処理フロー
サンプルコードを使い、処理フローを追いかける。
(a) 普通の関数outerを呼び出す(8行目)。
スコープチェーンが生成され、その中でフレームも作られる。

(b) outerが呼び出されたことで、その関数内でクロージャinnerが生成される(4行目)。
クロージャはそれが生成された時点での、つまり(a)のスコープチェーンを参照し保持する。

(c) innerが呼び出されると(12行目)、ここでは普通の関数の呼び出しと同じように
新しくスコープチェーンが生成され、その中でフレームが作られる。
だがしかし、新規に作ったスコープチェーンに(b)で参照し保持しているスコープチェーンも連結させる。

あとは繰り返し。


このように(a)、(b)、(c)の3つの規則でクロージャは実装できるわけだ。