12周年記念パーティ開催! 2024/5/10(金) 19:00

HTML5実力テストJavaScriptコース詳説 第1回 問題解説 その1

本シリーズでは、ピクセルグリッドが問題作成、2012年秋に公開された「第二回全国統一 HTML5実力テスト」JavaScriptコースの詳細な解説を行います。第1回目は、1〜5問目を解説します。

発行

著者 外村 和仁 フロントエンド・エンジニア
HTML5実力テストJavaScriptコース詳説 シリーズの記事一覧

はじめに

本シリーズでは、ピクセルグリッドが問題作成をした「第二回全国統一 HTML5実力テスト」JavaScriptコースの詳細な解説を行います。また、問題作成時の裏話やボツになった問題の紹介などもする予定です。

第一回目は1問目から5問目までを解説します。もしまだ受験されていない方はネタバレになってしまうので、ぜひ一度受験してから読んでみてください。

なお、HTML5関連の仕様は現在、草案段階であるものも少なくありません。ここでの情報は2012年11月末現在のものです。

setTimeoutの仕様に関する問題

[1] HTML5で規定されたsetTimeoutの最小時間を一つ選べ

  1. 2ms
  2. 4ms
  3. 8ms
  4. 16ms

答え. 2

解説

以前はsetTimeoutやsetIntervalに指定する時間の最小値はブラウザによって異なっていましたが、HTML5では4msと定められました。

setTimeout()メソッドの規定

次の例を見てください。

var count = 0;
var start = Date.now();

function loop() {
  count++;
  if (count > 100) {
    var time = Date.now() - start;
    var average = (Math.round(time / count * 10) / 10); // 小数点第一位で四捨五入
    alert('一回のループの平均時間: ' + average + 'ms');
  }
  else {
    setTimeout(loop, timeout);
  }
}

loop();

上記のtimeout値に0〜4を指定した場合、実行結果は同じになります。

実際のデモを見てみると、フォームにtimeout値を設定すると、1回のループの平均実行時間をアラート表示することができるのがわかります。

また、setTimeoutの場合は常に最小値が4msになるとは限りません。仕様書には次のようにあります。

5. If the currently running task is a task that was created by the setTimeout() method, and timeout is less than 4, then increase timeout to 4.

現在実行中のタスクがsetTimeoutによって作られたものであれば最小値が4msになるとあります。上記の例ではsetTimeout内でsetTimeoutを呼んでいて、以下のようにネストしている状態です。

setTimeout(function() {
  ...
  setTimeout(function() {
    ...
    setTimeout(function() {
      ...
      ...
    }, timeout);
  }, timeout);
}, timeout);

このような場合にsetTimeoutに指定したtimeoutの最小時間が4msに設定されます。

一方、以下の例でtimeoutを4より小さい値を指定した場合には4msにならないことが確認できます。

var start = Date.now();

setTimeout(function() {
  var time = Date.now() - start;
  alert('遅延時間: ' + time + 'ms');
}, timeout);

またsetInterval仕様書の記述は次のようになっています。

5. If timeout is less than 4, then increase timeout to 4.

これはsetTimeoutと違い、常に最小時間が4msになることを意味しています。

var count = 0;
var start = Date.now();

function loop() {
  count++;
  if (count > 100) {
    var time = Date.now() - start;
    var average = Math.round(time / count * 10) / 10; // 小数点第一位で四捨五入
    alert('一回のループの平均時間: ' + average + 'ms');
    clearInterval(timer);
  }
}

var timer = setInterval(loop, timeout);

setIntervalはtimeoutの値を4より小さくしても、最小時間は4msになります(コンマ以下の数値は誤差の範囲)。

Canvasの描画に関する問題

[2] 次のコードを実行した場合にcanvasに描かれる画像として正しいものを一つ選べ

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = 'rgba(224, 56, 56, 0.8)'; // 赤
ctx.fillStyle = 'rgba(224, 56, 56, 0.5)'; // 赤
ctx.arc(125, 180, 100, 0, Math.PI*2, false);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.fillStyle = 'rgb(183, 227, 180)'; // 緑
ctx.arc(225, 110, 62, 0, Math.PI*2, false);
ctx.fill();

ctx.beginPath();
ctx.fillStyle = 'rgba(93, 126, 251, 0.7)'; // 青
ctx.arc(150, 70, 38, 0, Math.PI*2, false);
ctx.fill();
        ol
            li 
            .ImgBox
                .ImgBox-body
                    img(style="border: 1px solid #ccc", src="https://s3-ap-northeast-1.amazonaws.com/codegrid/html5quiz/img/js_q2_1.png",data-src-shorten="http://bit.ly/Vbf6yV", width="190", height="190")
            li 
            .ImgBox
                .ImgBox-body
                    img(style="border: 1px solid #ccc", src="https://s3-ap-northeast-1.amazonaws.com/codegrid/html5quiz/img/js_q2_2.png",data-src-shorten="http://bit.ly/Vbf4XU", width="190", height="190")
            li 
            .ImgBox
                .ImgBox-body
                    img(style="border: 1px solid #ccc", src="https://s3-ap-northeast-1.amazonaws.com/codegrid/html5quiz/img/js_q2_3.png",data-src-shorten="http://bit.ly/Vbf6yY", width="190", height="190")
            li 
            .ImgBox
                .ImgBox-body
                    img(style="border: 1px solid #ccc", src="https://s3-ap-northeast-1.amazonaws.com/codegrid/html5quiz/img/js_q2_4.png",data-src-shorten="http://bit.ly/Vbf4XW", width="190", height="190")

答え. 1

解説

Canvasの描画に関する問題でした。赤、緑、青という順番に円を描画していって、どのような重なり順になるかといういうのが問題の焦点となります。結論からいうと、Canvasは描画した順番に上に重なっていくので、赤が一番下になり、続いて緑、青という順番で上に重なっていきます。したがって答えは1となります。

実際にどうなっていくか見ていきましょう。

まず最初の部分ですが、これはcanvasに図を書くための準備をしている部分です。

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

1行目でcanvas要素をHTMLから取得してきて、次にgetContextというメソッドで2Dのコンテキストを取得します。このようにして取得したコンテキストオブジェクト(ctx)に対してさまざまな処理を行うことで図を描画していくのがCanvasの特徴です。

次に赤い丸を描画している部分です。一行一行が何をしているのかわかるようにコメントをつけました。

// 新しい図を書き始める
ctx.beginPath();

// 枠線の太さは3px
ctx.lineWidth = 3;

// 枠線の色は赤(不透明度0.8)
ctx.strokeStyle = 'rgba(224, 56, 56, 0.8)'; // 赤

// 塗り色は赤(不透明度0.5)
ctx.fillStyle = 'rgba(224, 56, 56, 0.5)'; // 赤

// 中心の座標がx:125px, y:180pxで半径100pxの円をつくる
ctx.arc(125, 180, 100, 0, Math.PI*2, false);

// 枠線を描画
ctx.stroke();

// fillStyleの色で塗りつぶす
ctx.fill();

これを実行すると次のようになります。枠線が赤、塗り色が透明度0.5の赤の円が描かれます。

次に緑の円を描画している部分です。

// 新しい図を書き始める
ctx.beginPath();

// 塗り色は緑
ctx.fillStyle = 'rgb(183, 227, 180)'; // 緑

// 中心の座標がx:225px, y:110pxで半径62pxの円をつくる
ctx.arc(225, 110, 62, 0, Math.PI*2, false);

// fillStyleの色で塗りつぶす
ctx.fill();

これを確認すると、さきほどの赤い円の上に緑の円が描かれるのがわかります。

最初の円の上に2番目に書いた緑の円がのっているのがわかると思います。Canvasはこのように書いた順に上に積み重なって描画されます。

最後の青い円を描画して完成です。

// 新しい図を書き始める
ctx.beginPath();

// 塗り色は青
ctx.fillStyle = 'rgba(93, 126, 251, 0.7)'; // 青

// 中心の座標がx:150px, y:70pxで半径38pxの円をつくる
ctx.arc(150, 70, 38, 0, Math.PI*2, false);

// fillStyleの色で塗りつぶす
ctx.fill();

描画結果は次のように、一番上(最前面)に透明度0.7の青い円が描かれます。

DOM4のmutation methodの仕様に関する問題

[3] DOM4(W3C Working Draft 5 April 2012)で定義されたmutation methodのうち存在しないものを一つ選べ

  1. before
  2. appendTo
  3. prepend
  4. replace

答え. 2

解説

DOM4の草案にMutation methodsというものが提案されています。

DOM4(W3C Working Draft 5 April 2012)

Mutation methodsはDOMツリーの構造を変化させるためのメソッドで、現在のDOMのメソッドではinsertBeforeappendChildreplaceChildremoveChildなどがあり、これらはDOM4の草案ではLegacy mutation methodsと位置づけられています。

DOM4に草案に現在定義されているMutation methodsは以下の6つです。

  • prepend
  • append
  • before
  • after
  • replace
  • remove

例えばこれまで、ある要素の最初に子要素を追加したいといった場合に、次のようにする必要がありました。

HTML

<div id="elem">
  <!-- ここに新規要素を追加したい -->
  <div>current text</div>
</div>

JavaScript

var elem = document.getElementById('elem');
var newElem = document.createElement('div');
newElem.innerHTML = 'new text';

elem.insertBefore(newElem, elem.firstChild);

このようにinsertBeforefirstChildを組み合わせて実装することは可能ですが、直感的ではありません。DOM4のMutation methodsを使うと最後の行は次のように書くことができるようになると思われます。

elem.prepend(newElem);

これはとても直感的です。その他にもbeforeafterremoveなど、これまでだと少し面倒な記述をしないといけなかったものがjQueryのように直感的に書くことができるようになる可能性があります。

これらのメソッドの仕様はまだ草案段階で、この通りに仕様の策定やブラウザへの実装が進むとは限りません。ですが、将来的にブラウザに実装されて普通に使うことができるようになれば、jQueryを使わなくても簡単にDOM操作ができるようになるかもしれません。

WebGLに関する問題

[4] 2011年3月にWebGL1.0が正式な仕様となった。WebGLの仕様を管理している団体を一つ選べ

  1. IANA
  2. Ecma International
  3. W3C
  4. Khronos Group

答え. 4

解説

IANAはInternet Assigned Number Authorityの略で、IPアドレスやドメイン名などインターネットに関連する番号を標準化・管理する組織です。

Ecma Internationalは情報通信技術における国際標準化団体で、JavaScriptの元になっているECMAScript(ECMA-262)の標準化を行っていることで有名です。その他にもC#などの標準化を行っています。

W3Cは、ご存知のようにHTMLやXML、DOMなどWebに関する技術などを仕様策定や標準化を行っている団体です。ハイパーテキストやWWWの生みの親であるティム・バーナーズ=リーによって設立されました。

Khronos GroupはOpenGLを始めとするさまざまな3DCG技術の仕様を管理している団体です。WebGLもKhronos Groupで管理されています。また、WebGLの仕様の策定にはApple、Google、Mozilla、Operaなども参加しており、これらのベンダーのブラウザでは、試験的実装など、すでにWebGLを利用する準備が始められています。

なお、WebGLはCanvas要素に3Dグラフィックスを描画するというものですが、Canvasの2DコンテキストはW3Cで仕様の策定が行わており、完全に別の仕様となっていますので注意が必要です。

コラム:問題作成裏話

4問目の問題は当初、WebGLのコードが登場し、WebGLを書いたことがある人でないとわからないような、非常に難易度が高い問題でした。しかし、あまりに難しすぎて誰もわからないだろうということでボツとなり、比較的簡単に変更したのがこの問題です。

そのようなにボツなった問題も本シリーズの最後にまとめて紹介する予定ですのでお楽しみに!

SVGのコードに関する問題

[5] text/html のHTMLソースのbody内に次のSVGコードを埋め込んだ場合、a要素からアラートが出せるものを一つ選べ

<svg width="300" height="200">
  <a href="javascript:alert( 'clicked' );">
    <circle cx="150" cy="100" r="50"/>
  </a>
</svg>
<svg width="300" height="200">
  <a xlink:href="javascript:alert( 'clicked' );">
    <circle cx="150" cy="100" r="50"/>
  </a>
</svg>
<svg width="300" height="200">
  <a svg:href="javascript:alert( 'clicked' );">
    <circle cx="150" cy="100" r="50"/>
  </a>
</svg>
<svg width="300" height="200">
  <a path="javascript:alert( 'clicked' );">
    <circle cx="150" cy="100" r="50"/>
  </a>
</svg>

答え. 2

解説

HTML5では、SVGやMathMLなどポピュラーな外部XMLについては名前空間を宣言する必要がなく、暗黙のうちに該当語彙のルート要素で名前空間が宣言されます。

一方で、要素から見た外部XMLの属性については、名前空間を宣言する必要はないものの、あらかじめ決められた接頭辞をつけることになっています。XLinkの接頭辞はxlink:と決められているため、xlink:hrefを付与したa要素が動作します。

なおsvgタグ内のa要素は、たまたまHTMLのa要素と同名ですが、SVGに属しているa要素であり、普段よく目にするHTMLのa要素ではありません。

2.9 Namespaces — HTML5

8 The HTML syntax — HTML5

実際にクリックしてアラートが表示されるか確認してみましょう。ChromeやFirefox、IEの9以降などのブラウザではHTMLに直接SVGを書いて表示することができるので、次のように書けば確認できます。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>SVG</title>
</head>
<body>
<svg width="300" height="200">
  <a xlink:href="javascript:alert( 'clicked' );">
    <circle cx="150" cy="100" r="50"/>
  </a>
</svg>
</body>
</html>

結果は次のように、xlink:hrefで指定されたアラートが表示されます。

次にxlink:hrefhrefにして、こちらがクリックしても何もおきないことを確認してみましょう。次の例がhrefに変更したものです。

このように、hrefではクリックできないのがわかります。

まとめ

今回は1問目から5問目を解説しました。次回は6問目から10問目です。JavaScriptの細かい挙動の問題やセキュリティ関連の問題などがあります。次回もお楽しみに!