ソースのバグの作り方 -if文のカッコ-

先日の記事「最新記事だけ日付を消す新スクリプト -お知らせ枠の設置-」のソースを実際にマスクドライダー17号さんが設置したところ、次の事情でうまくいきませんでした。(記事のソースは、うまくいくように修正済みです)

最初のソースコードは、次のものでした。

<script type=”text/javascript”>date=document.querySelector(‘div.entryDate’);if(date){date.style.display=’none’;}</script>

このコードは、間違っていません。
実際に、マスクドライダー17号さんのブログのソースをメモ帳にコピペして、上の通り作業してブラウザで開くと、ちゃんと消えたのに、本当のブログにアップロードすると、消えませんでした。

なぜかというと、{} の2つのカッコが、おかしな形で変換されていたのです。

ファンブログのエディタを通すと、時々なぜかわからない形でソースコードが変わってしまうことがあります。それで、ソースを書き換えて対処しました。

変更点は、次の通りです。(記事のソースは変更済みです)

{} を削除する。
おかしく変換されてしまう2つの文字を削除することで、おかしな部分がなくなったので、正しく動きました。

なぜ、{} を削除できたのか?

逆に言うと、{} は不要なものだったのか?という疑問があるかもしれません。この場合は、なくてもいいものでした。だから、消すだけで対処できました。これは次の条件にあっていたためです。つまり幸運だったのです。

if文の次の処理は条件にあえば実行される。実行する処理が複数ある時はその部分を、{ と } で囲む。

JavaScriptに限らず、C系統のif文の書き方は次の構文です。

if(条件){ 実行内容 }

今回の場合は、if(date){date.style.display=’none’;} が、その部分です。

これは、if(‘object’==typeof date){date.style.display=’none’;} と書きかえても同じです。

この文を日本語に直すと、dateがオブジェクトなら、dateのスタイルシートdisplayをnoneにしなさいとなります。

これは実行内容がひとつです。「dateのスタイルシートdisplayをnoneにしなさい」のひとつだけを実行するので、カッコがなくても正しく動きます。しかし、もし実行内容が複数だと意図どおりには動きません。

たとえば、「dateがオブジェクトなら、dateのスタイルシートdisplayをblockに、色を赤にしなさい」という内容であったらどうでしょう。ソースコードはこうなります。

if(date){
	date.style.display='block';
	date.style.color='#ff0000';
}

改行と行のはじめの空白(インデント)は見やすくするためにつけていますが、コンピュータの内部処理では無視されます。if(date){date.style.display=’block’;date.style.color=’#ff0000′;}と書いたのと同じようにコンピュータは処理するのですが、人間が見やすくするためにつけています。

JavaScriptでは、{から}までのブロックは、ひとつの命令として扱います。

これで、dateがオブジェクトなら、{から}までのブロックを実行しなさいとなります。ブロックの内容は「displayをblockに」と「色を赤に」の2つです。

ここでカッコをとってみます。

if(date)
	date.style.display='block';
	date.style.color='#ff0000';

これはどのように扱われるか?次のようになります。

処理1. dateがオブジェクトなら、dateのスタイルシートdisplayをblockにしなさい。
処理2. dateのスタイルシートのcolor(色)を#ff0000(赤)にしなさい。

処理1はdateがオブジェクトならという条件判断をされますが、条件判断はひとつ目の処理で終了します。よって、処理2はdateがオブジェクトであろうとなかろうと実行します。

この例だとdateというオブジェクトがあれば、結果は同じです。カッコがあってもなくても、「dateがオブジェクトであった場合」の結果は、「スタイルシートのdisplayをblock」にして「スタイルシートのcolorを#ff0000」にします。

dateがオブジェクトである限り、カッコがあってもなくても、思ったとおりの結果になるのです。だから例えば、この命令をマスクドライダー17号さんのブログに適用すれば正しく、意図どおりに動きます。なぜなら、マスクドライダー17号さんのブログでは日付が消えているのだから、dateオブジェクトがあるのです。

しかし、dateがオブジェクトでなかったら、どうなるでしょう?適用されるはずのdate.style.colorが存在しないかもしれません。その場合はエラーになります。だから他の人のブログで使えばエラーが出るかもしれません。

つまり、これはカッコがないことによって気がつかないバグになっています。

カッコのあるなしで、意図とは違う結果を生み出すことがあります。バグというのはそうやって生み出されるのです。

最新記事だけ日付を消す新スクリプト -お知らせ枠の設置-

先ほど「querySelectorとquerySelectorAll」という記事を書きましたが、実はあれ、この記事の前フリです。

楽して稼ぎたい」のマスクドライダー17号さんなんですが、ブログを開くと最新記事を「お知らせ」欄として使っています。

最新記事を未来の日付にすれば、一番上に表示されるので、「お知らせ」を書いて常に表示できます。

問題なのが、しばらくの間「2017年05月27日」と表示されているんですね。待っていれば消えるんですけど。

どうやって消しているのかというと、スクリプトを使っています。そのソースを変えれば、もっと早くに、すぐ消えるんじゃないか?と、思ってソースを見てみました。実にドンくさいソースコードでした。

でもよく考えたら、これは私が書いたものでした

そのソースコードが、これですが、無駄に長い。「記事の日付を消したい」より

<script type="text/javascript">(function(){var entries=document.getElementById('entries');if(!entries){return;}var div=entries.getElementsByTagName('div');if(!div){return;}for(var i=0;i<div.length;i++){if(div[i].className=='entry'){var child=div[i].getElementsByTagName('div');if(child){for(var n=0;n<child.length;n++){if(child[n].className=='entryDate'){var date=child[n].innerHTML.replace(/^\s+|日\s*$/g,'').replace(/年|月/g,'/').split('/');var entrydate=new Date(date[0],date[1]-1,date[2]);var today=new Date();if(today.getTime()<entrydate.getTime()){child[n].style.display='none';div[i].className='entry future';break;}return;}}}}}})();</script>

これを、先ほどの記事「querySelectorとquerySelectorAll」を使って書きかえます。

まずは、古いコードをスキンから削除してください。もういりません。そして、この下のコードを使います。

新しいソースコード

<script type="text/javascript">date=document.querySelector('div.entryDate');if(date)date.style.display='none';</script>

すごく短くなった。querySelector恐るべし!

ただし、手を抜いています。最新記事の日付は常に未来である。その記事は必ず先頭に表示される。そういう前提で作りました。

設置方法

これを、スキンではなく、「2017年05月27日」の日付の記事の中に付け加えます。

張り付けるのは、記事の最初でも最後でも構いません。
問題がなければ、「2017年05月27日」の日付はソッコーで消えます。


追記

実際にマスクドライダー17号さんが設置したところ、ある事情でうまくいきませんでした。
(上のソースは、うまくいくように修正済みです)

それに関して別の記事「ソースのバグの作り方 -if文のカッコ-」で説明しています。

Google Analyticsでクリック数を計測するスクリプト

Google Analyticsでクリック数を計測できるんですね。知りませんでした。

今回の記事の元ネタは「ファンブログハック」のおーとえす氏の記事「googleアナリティクスで簡単にクリックカウント出来るコード」です。おーとえす氏の場合は、JQueryを使っているんですが、使わないコードを書いてみました。

このスクリプトだと、Tweetボタンを押しても反応しなくなります。下にある修正版を使ってください。

<script type="text/javascript">
<!--
(function(){
  var a=document.querySelectorAll('a');

  for(var i=0;i<a.length;i++){
    a[i].onclick=(function(elem){
      return function(){
        var type=(-1==elem.href.indexOf('/ayzfqir5/')&&'javascript:void(0)'!=elem.href)?'Out':'In';
        _gaq.push(['_trackEvent',type+'bound Links','click',elem.href,0]);
      };
    })(a[i]);
  }
})();
// -->
</script>

青い字で書いてある0の数字をスキンごとに変えると、どのスキンでクリックされたかがわかります。数字は0以上であれば何でも構いませんが、マイナスの値だとダメみたいです。
これは、合計値が表示されるみたいで、この使い方では意味ありませんでした。

上のコードでTweetボタンが動かなくなった技術的説明

Tweetボタンは、aタグを使って、href=”javascript:void(0)”onclick=”ここでスクリプト処理”というソースですが、上のコードは、onclick=function()という形で、onclickを上書きしてしまいました。

修正コードでは、上書きではなく追加という形に変更しました。詳しくは別記事「aタグをボタン代わりに使う」と「addEventListenerとattachEvent」を、ご覧いただくのがいいと思います。

修正版はこの下のものです。

<script type="text/javascript">
<!--
function add_ga(elem){
	var type=(!elem.href.match(/^[^\?]+ayzfqir5/)&&elem.href.match(/^[^\?]*\/\//))?'Out':'In';
	_gaq.push(['_trackEvent',type+'bound Link','click',elem.href]);
};

(function(){
	var set_event=(function(){
		if(document.addEventListener){
			return function(elem){
				if(null!==elem.onclick){
					elem.addEventListener('click',elem.onclick,false);
				}

				elem.onclick=function(){add_ga(elem);};
			};
		}

		if(document.attachEvent){
			return function(elem){
				if(null!==elem.onclick){
					elem.attachEvent('onclick',elem.onclick);
				}

				elem.onclick=function(){add_ga(elem);};
			};
		}

		return null;
	})();

	if('function'==typeof set_event){
		var a=document.querySelectorAll('a');

		for(var i=0;i<a.length;i++){
			set_event(a[i]);
		}
	}
})();
// -->
</script>

ちょっと変なスクリプトに見えるかもしれませんが、単にイベントを追加しただけではクリック数は保存されませんでした。詳細な説明は別記事にしましたので、よければご覧ください。「Google Analyticsのイベント トラッキングはaddEventListenerやattachEventでは計測されない

このコードを、スキンの最後の方にある</body>の直前に追加すれば、すべてのクリックが計測出来るようになります。

ただし、赤い字で書いてあるayzfqir5を自分のURLに差し替えてから使ってください。

この記事を書いた移転前のブログはhttp://fanblogs.jp/ayzfqir5/というサブディレクトリ方式のURLでした。このayzfqir5の部分を自分のURLを見て、自分のブログだけに出現する物に書き換えてください。

URLの中にayzfqir5が含まれているかどうかを判断材料にして、内部リンクか外部リンクかのログを取っています。内部リンク(自分のブログへのリンク)ならInbound Link、外部リンク(自分のブログ以外へのリンク)ならOutbound Linkというイベント カテゴリにわけて記録されます。

Google Analyticsでの見方

「コンテンツ」タブの「イベント」でログを閲覧できます。

下は、このブログでどこへのリンクがクリックされたかを表示した物です。今つけたばかりなので数は少ないです。

この表のイベントの値というのが、上でスキンごとに変えた数字です。(合計値が表示されて意味がないので今は使っていません)

Google Analyticsの管理画面
クリックすると別画面で大きく見られます

下のInbound Linksが内部リンク、Outbound Linksが外部リンクです。

内部リンクと外部リンク
クリックすると別画面で大きく見られます

querySelectorとquerySelectorAll

スタイルシートのセレクタを使ってDOMにアクセス出来る2つのメソッドが超便利な件。

querySelectorquerySelectorAllの2つ。

どちらも同じで、document.querySelector(‘div.entry p’)のようにセレクタでアクセスできる。

この2つのメソッドの違いは、querySelectorの場合、指定条件にあった最初の1個だけを抽出する。
一方、querySelectorAllの時は、指定条件にあうすべての要素を抽出する。

たとえば、次のようなHTMLがあったとする。

<div class="entry">
<p class="hoge">こんにちは。<br />
今日はとっても天気がいいですね!</p>
<p>これはペンです。</p>
<p class="hoge">さようなら。</p>
</div>

これに対してpタグを見つけたい場合

document.querySelector(‘div.entry p’)だと、最初の
<p class=”hoge”>こんにちは。<br />
今日はとっても天気がいいですね!</p>

だけを抽出する。

一方、document.querySelectorAll(‘div.entry p’)なら<div class=”entry”>~</div>の中にある、
すべてのpタグをまとめて抽出してくれる。

そして、querySelectorAllは、配列のように添字でアクセスできる。

var p=document.querySelector('div.entry p');
p.style.color='#ff0000';

とすると、
こんにちは。
今日はとっても天気がいいですね!

というように、最初のpタグだけが赤くなる。

一方

var p=document.querySelectorAll('div.entry p');

for(var i=0;i<p.length;i++){
	p[i].style.color='#ff0000';
}

とすれば、すべてのpタグが赤くなる。

querySelectorAllには、lengthがあるが、querySelectorには、lengthがないので注意。

セレクタでアクセス出来るので、var p=document.querySelectorAll(‘div.entry p.hoge‘);と指定すれば、
hogeクラスのpタグだけが抽出される。

CSSのセレクタに関しては次のページが参考になります。
意外と知らない!?CSSセレクタ20個のおさらい|Webpark

本当にこれは便利です!
実際にこのメソッドを使ってソースを書いてみました。下がその記事です。

なぜ私はサイドバーを右にしたか?

前回の記事「経験からクリック率が高いと思う場所」にコメントありがとうございました。

結論から言うと、このブログの右サイドバーに何か置いても、目に入らない。
目に入らないのだから、たとえばそれが広告であったとしてもクリックされない。

そういう結論になるわけですが、その結果が得られただけでも実験の成果はあったと思います。

書いてあることが、広告ではなく、読者の利益になることなのだから、敬遠された結果ではない。
純粋に目に入らないポジションなんだと思います。

今回は、その結果に関する考察です。

まず、いただいたコメントで気になるのが、Rさんが書かれたこれ。

デザイナーさんから教えて頂いた、人間の視線の習慣は
左から右、上から下。メインのコンテンツ見ながら
視線を下におろすと、いってらっしゃる場所は見ないです。
私の場合、かもしれませんが。

結論はRさんの場合だけでなく、みんな見なかった。

Rさんも、自身の記事「無料プレゼント(Amazon編) たかがアフィリ」で薦めているアマゾンの公式ブログに、こう書いてあります。Amazon アソシエイト・プログラム(アフィリエイト) 公式ブログ: 「ユーザーは説明を読まない」~短時間でアピールするサイトデザインより

Webサイトを閲覧するとき、人の眼は左から右に、上から下へと動きますから、必然的にページの左上が至上の場所となります。通常Webサイト名や、ロゴ、サイトの簡単な説明などの重要な情報はこの位置に置くことになります。もしもあなたのサイトのタイトルに、サイトの内容を想像できる言葉を使用していない場合は、ページトップ上部で、内容を「ごく簡単に1行程度で」説明しておくと、ユーザーが内容を理解する手掛かりになります。

このブログ記事は自分もアフィリエイトをはじめた時に読んで、非常に参考になると思いました。
今回、テンプレートを作り替える際も、念頭にはありました。

でも、このブログでは敢えて、右にサイドバーを置いています。
これは意識的にやっています。ですから、記事中に広告を入れない限り、広告スペースも右になります。

記事中に四角いスペースの広告を置くなら、自分は左に置きます。
理由は、上に書いてある通りです。

Yahoo!JAPANのトップページの広告は右上

敢えて、サイドバーを右にしたのには、3つの理由がありました。
そのひとつが、「Yahoo! JAPAN」のトップページです。

Yahoo! JAPANはトップページの広告を右上に置いています。
自分がはじめてYahoo! JAPANのページを見たときから、これは変わらない。

ということは、Yahoo! JAPANとしては満足できる結果がでているのではないか?と考えました。
自分より人気サイトがやっているのだから、真似てみる。これは、ひとつの考えだと思います。

日本の新聞は基本、右上から読みはじめる縦書き

Yahoo! JAPANは、なぜ広告を右の上に配置したのでしょうか?
それは、私にはわかりません。

ただ、最初に上の、アマゾンのブログを見た時から、ずっと思っていた感想があります。
「それは欧米人の考えだ!」

産経新聞などは違いますが、朝日新聞や東スポは縦書きです。
特に「東京スポーツ」にとって、右上の縦に書いた見出しの出来は死活問題です。

東スポのレイアウトは、東スポWebにある「本日の紙面」で確認出来ます。

東京スポーツ – Wikipedia」より

「マドンナ痔だった」、「落合家チンポ丸出し放送」、「聖子輪姦」、「人面魚重体」、「大仁田爆死」、「フセインインキン大作戦」、「ダイアナ大胆乳」、「阪神次期監督上岡龍太郎」、「宇宙人化石発掘」「小向美奈子殺される」など、1面の奇抜な見出しが特徴。これらの見出しの下には小さく「?」「か」「も」「説」「絶叫」などの言葉が書かれ濁されていることが多いが、それらは新聞スタンドに陳列されている状態や折りたたんである状態では見えないように紙面のつくりが計算されている。

東スポの見出しは、ロマンだ!いや、そんなことはいい。
日本人は縦にものが読めるのです。

野茂英雄がアメリカ大リーグに渡って大成功したのはフォークボールという武器があったから。
フォークボールとは、縦に落ちる変化球です。

この当時、誰だか忘れましたが、これを解説してこんなことを言っていました。

「日本人は本を読むときでも、縦に目を動かすことに慣れている。欧米人がフォークボールを打てないのは、横書きだからじゃないか?」

これは、問題点を言い得ているのではないでしょうか?
そうだとしたら、生活習慣で、目の動き、目につく場所というのは変わるのでは?

そう考えたのが、もうひとつの理由です。
しかし、ブログその物が、左から右への横書きである以上、この考えは当てはまらないのかもしれません。

「Yahoo!JAPAN」の広告は右上、「東京スポーツ」の見出しは右上(「か?」は折り目の後に来るようにする)
こういったことから、このブログではアフィリエイトのスペースを右に用意しました。

スクロールバーは右にある

そしてサイドバーを右にした、もうひとつの理由は「ユーザビリティ」の向上です。

ブラウザのスクロールバーは東洋、西洋関係なく、OSの種類も関係なく、みんな右側にあります。
これは、人間の多くが右利きだからです。

マウスを持つのは、多くの場合、右手です。そのマウスに近い所に操作関連のものはあった方がいい。
スクロールバーが右にあるのは、そういう理由だったはずです。

つまり、マウスで操作するもの、ドラッグしたり、クリックしたりするものは1ヵ所に集めた方がいい。
そう思って、スクロールバーの近くにサイドバーを持ってきました。

結論

結果として、読者が意識して探す物は右で問題ない。
ただし、意識して探さない広告などは、目につかない確立が高いのでは?

というデータになりました。
今後、さらに、実験と分析を進めていきたいと思います。