11/23 学んだこと(html, js)

コンピュータでは文字集合(Character Set)をエンコード方式に従って符号に変換して扱う。

  • は何のために書くのか

lang によって表記が異なることがある。lang=en にしても何も変わっていないように見えるが、変わることもある?

  • 指数の扱い方

2e+2 は 2 * (10の 2 乗)

  • === と == の違い

=== は型まで含めた比較で、== は値だけの違い。
↓を実行してみるとわかりやすい。
1 == "1";
1 === "1";

N予備校プログラミングコースがものすごくよい

自分はプログラミングはちょっと触ったことがある程度。
すごく簡単な javascript はかけるほど、それぐらいの知識。
もう少しできることを増やしたくて、これを始めてみた。

今はプログラミング入門 Webアプリのごく初歩までやったところ。
javascript で alert(25 + 25); を書くのに chrome のインストールからはじめて 2 時間ぐらいかけているけど、ちゃんと双方向コミュニケーションが成り立っていて面白い。

ニコ動みたいに他のユーザが書いたコメントが見れるのだけどこれがよくて、「自分の中では疑問という形になっていないけど、曖昧なところについて他の生徒が質問して、講師がそれに答えてくれる」っていうのがすごく良い。
まだ始めたばかりだけど、自分が知っていることに関しても背景知識を講師の先生が説明してくれていて、これは本や web では調べないと学べないところなので、こういったことが受動的に学べてすごくありがたい。
(たとえば VS Code がどんな言語で書かれているかなど)

あと知識とは違うけど、わからないところに講師の先生がリアルタイムでこたえてくれるっていうのが見てて本当に嬉しくなる。
自分が高校生だった頃、わからないことがあったときも他の人の迷惑になるから授業が終わるまでは質問できなくて、残りの授業時間はずーーーーーーーーっといらいらしながら過ごしていたので、これが私が受けたかった授業だ!って思ってすごく嬉しい。

まだ自分が知っているところしかやっていないので知識というほど知識は身についていないけど、これをずっとやり進めたら色々できるようになるのかなあ、と思うととても楽しみ。

しかし授業も資料もよく出来ていて、先生のレベルもすごく高いのに月額1000円って安すぎて心配になる。

関数の巻き上げ

かなり久しぶりのブログ。幸いにして仕事で javascript を使う機会にも恵まれ、なんとか chrome extension を作ったりしていた。
やっぱりちゃんと動くものが作れると楽しい。
勉強していたテキストがまだあと少し残っているからさっさと終わらせよう。
ちなみに仕事で書いている時に引っかかってしまったのが「関数の巻き上げ」。
知らないと怖い「変数の巻き上げ」とは?|もっこりJavaScript|ANALOGIC(アナロジック)
こちらにとても詳しく書いてあって助けられた。知らないとこれ辛い。。

さて、macjavascript で開発するときは最近 aptana studio を使っていたんだけど、windows でも開発したくなって Cloud9 というオンライン上の開発環境を利用してみることにした。
うまく使えるといいんだけど。

オブジェクトとかコンストラクタとか

前回に引き続き、これまでの振り返りで自分の理解が怪しかったところのまとめ。主にオブジェクトとかコンストラクタとか。

new がつくときとつかない時の違い

var obj = new Constructor();
function Constructor(){
	document.write("こっちはコンストラクタ");
var obj1 = Constructor1();
function Constructor1(){
	document.write("こっちは単なる関数の参照");
}

オブジェクトの初期化の使い分け。

オブジェクトのインスタンスを作成してプロパティやメソッドを定義する方法には2つある。

  • new 演算子を使う。
  • オブジェクト初期化子を使う。

特にそのオブジェクトが何度も使われるようなたぐいのものであれば、前者でさらにコンストラクタを使うと楽。
そういったケースでないのであれば、インスタンス作成とプロパティ、メソッド定義を同時にやりたいのであればオブジェクト初期化子、別々にやるのであれば new 演算子を使う。

コンストラクタの中にある処理って何?

コンストラクタにはプロパティがーとかメソッドがーとかいう説明を散々読んだところでひとつの疑問がわいた。
コンストラクタの中で行われている処理ってプロパティでもメソッドでもないけどなんなの?
単なる処理だけど、色々読んだ結果コンストラクタの中に入っているのはプロパティかメソッド(メソッドもプロパティの一つだけど)のはず。じゃあ処理ってなんなんだろう?

var obj2 = new Constructor2("これなに?");
function Constructor2(test){
	this.test = test;
	document.write(this.test);
}

このコンストラクタの中の this.test はわかる。初期化している。じゃあ、document.write はなんなのか。
コンストラクタは初期化を行うものって書いてあるけど、document.write は初期化と呼べるのか。
ここに関してはとても悩んだのだけれど、調べていくうちに「そもそもコンストラクタ内部では初期化のみを行ったほうがよくて、複雑な処理は避けるべき」といった文書を見つけて疑問が氷解。そうか、そもそもこのコンスタラクタの書き方が良くない。
一般的には処理はコンストラクタの中に入れないからあまり言及されていないのか。コンストラクタの中では基本的にはプロパティかメソッドの定義が入るはずなので、こういった処理を行うことが想定されていないから言及がないのだ。
ちなみに、↑のコードをこの考え方で書き直すとこんな感じ。

var obj3 = new Constructor3("これでいいんじゃないかな。");
document.write(obj3.test);
function Constructor3(test){
	this.test = test;
}

プロトタイプ

一つのオブジェクトのインスタンス間で共通して使いたいものはプロトタイプにしておく。そうでなければ各インスタンスに直接突っ込めば良さそう。

とりあえずこんな感じ。オブジェクトは一通り理解できた、と言えればいいんだけど、もうちょっと慣れが必要な気がする。
とりあえずはテキストのオブジェクトの関連のところ、最初から全部やり直してみるー。

ここまでの振り返り

今日まで勉強してきた Javascript で、自分の理解が甘いところをまとめてみる。

クロージャ

まずは定義。

関数内に出現する自由変数(関数内で宣言されていない変数)の解決の際、実行時の環境ではなく、関数を定義した環境の変数を参照できるようなデータ構造。

クロージャとは - はてなキーワード
これに対して Mozila の説明がわかりやすかった。

クロージャ - JavaScript | MDN

function makeFunc() {
  var name = "Mozilla";

  function displayName() {
    alert(name);
  }
  return displayName;
}

var myFunc = makeFunc();

myFunc();

var myFunc = make Func(); の時点では displayName が指すオブジェクトを myFunc に割り当てているだけで displayName() の実行はされていない。
displayName() が実行されるのは myFunc() のところ。
なので、これが実行された時は name が定義されていないことになるが、問題なく動く。
なぜなら、これは実行時の環境ではなく定義した時点での環境の変数が参照されるから。

クロージャを使うメリットに関してはこれがわかりやすかった。
今までアクセスを限定することに寄って値の操作などを防ぐ、というメリットしか知らなかったが、このブログによって計算量が減るということがよく理解できた。

私が今までクロージャを理解できなかった理由 - 主にプログラムを勉強するブログ

コンストラクタ

コンストラクタとプロトタイプがいまいちわかっていなかった。
今日復習してわかるようになった気がするけど、まとめるのはまた後日。。

プロトタイプとコンストラクタ

仕事が始まった。予想通りだけど平日は JavaScript の勉強をする時間がとれないので、今日は一週間ぶりの勉強。
まあでも、仕事で早速 Chrome の extension を作ってみたらとてもすんなりと思った通りのものが作れてとてもうれしかった。勉強した甲斐があったなあ。

で、今日勉強したことはプロトタイプとコンストラクタ
コンストラクタは前から何度も使っていたけど、自分で定義したのは初めて。
教科書に従ってこんなのを書いてみた。

function Book(title, author, asin, thumbnailURL){
	this.title = title;
	this.author = author;
	this.asin = asin;
	this.thumbnailURL = thumbnailURL;
}

プロトタイプも試してみた。

Book.prototype = {
	showTextLink : function(target){
		var link;
		link = "<a href = 'http://www.amazon.co.jp/exec/obidos/asin/";
		link += this.asin + "'";
		if(target){
			link += " target='" + target + "'";
		}
		link += ">" + this.title + "</a>";
		
		alert(link);
		document.write(link);
	},

で、これを書いているうちに疑問がひとつ出てきた。
コンストラクタでプロパティを定義するのとプロトタイプで定義するのと何が違うんだろう?
例えばこんな書き方したっていいんじゃないの。

function Book(title, author, asin, thumbnailURL){
	this.title = title;
	this.author = author;
	this.asin = asin;
	this.thumbnailURL = thumbnailURL;
	this.showTextLink= function(){
	...
	};
}

この疑問に答えてくれたのがこちらのブログ。

JavaScriptの「プロトタイプ入門」 - Qiita
つまり、コンストラクタでプロパティとして定義してしまうと、毎回そのオブジェクトのインスタンスが生成される度に関数が定義されてしまう。
なので、それを避けるためにはプロトタイプとして関数を定義すると良い。
このブログのお陰で疑問点がすぐ解決できてよかった!

全角英数字を半角英数字に変換する方法

DOM のお勉強をしている最中に出てきたサンプルコード、全角英数字を半角英数字に変換する、というものの解法が面白かった。
Unicode の表を見てみると例えば全角の A は 0xFF21 で半角の A は 0x41 で、差分は 0xFEE0 となる。全角英数字と半角英数字の並びは同一なので、この値は B, C …とずっと一緒となる。
なので全角英数字を半角英数字にするためには 0xFEE0 を引けばいい。
参考:
Unicode一覧 F000-FFFF - Wikipedia
Unicode一覧 0000-0FFF - Wikipedia
書いてみたコードはこれ。body タグ以下のすべてのノードの全角英数字を半角英数字にしている。

function load(){
	var body = document.getElementsByTagName("body")[0];
	recursive(body);
}
function recursive(body){
	for (var i = 0; i < body.childNodes.length; i ++){
		var cNode = body.childNodes[i];
		if(cNode.nodeType == 1){
			// 要素ノード
			recursive(cNode);
		}
		else if(cNode.nodeType == 3){
			// テキストノード
			cNode.nodeValue = convert(cNode);
		}
	}
}
function convert(cNode){
	var num = cNode.nodeValue.length;
	var str = "";
	var flag = false;
	for(var i = 0; i < num; i++){
		var cha = cNode.nodeValue.charCodeAt(i);
		if(cha >= 0xFF10 && cha <= 0xFF19 || cha >=0xFF21 && cha <= 0xFF3A || cha >=0xFF41 && cha <= 0xFF5A){
			// 変換処理
			flag = true;
			cha -= 0xFEE0;
		}
		str += String.fromCharCode(cha);
	}
	if (!flag){
		return str;
	}
	else{
		return cNode.nodeValue + ":" + str;
	}
}

それにしても DOM って名前しか聞いたことなかったけど、書いてみたらすごく便利。あと思うように操作できて楽しい!