diff --git a/public/stage1/tests.js b/public/stage1/tests.js index 46f1ed45..970a6d63 100644 --- a/public/stage1/tests.js +++ b/public/stage1/tests.js @@ -12,7 +12,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を document.getElementById(elementId) に // 書き換え、ブラウザをリロードしてみてください。 var elementId = 'firebrick'; - var element = 'change me!'; + var element = document.getElementById(elementId); expect(element).to.be.instanceof(HTMLElement); expect(element).to.have.property('id', elementId); @@ -27,7 +27,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を書き換えてください。 var elementId = 'chocolate'; - var element = 'change me!'; + var element = document.getElementById(elementId); expect(element).to.be.instanceof(HTMLElement); expect(element).to.have.property('id', elementId); @@ -41,7 +41,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を書き換えてください。 var elementClassName = 'mediumseagreen'; - var elements = 'change me!'; + var elements = document.getElementsByClassName(elementClassName); expect(elements).to.have.length(1); expect(elements[0]).to.have.property('className', elementClassName); @@ -55,7 +55,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を書き換えてください。 var elementClassName = 'turquoise'; - var elements = 'change me!'; + var elements = document.getElementsByClassName(elementClassName); expect(elements).to.have.length(2); expect(elements[0]).to.have.property('className', elementClassName); @@ -70,7 +70,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を書き換えてください。 var elementTagName = 'blockquote'; - var elements = 'change me!'; + var elements = document.getElementsByTagName(elementTagName); expect(elements).to.have.length(1); expect(elements[0]).to.have.property('tagName', elementTagName.toUpperCase()); @@ -93,7 +93,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // すると、開発ツール上で
  • ... が選択されます。 // このことから、7 番の赤色の要素の ID は brown だということがわかります。 // では、'change me!' を document.getElementById('brown') に書き換えてみましょう。 - var element = 'change me!'; + var element = document.getElementById('brown'); expect(element).to.have.property(secret('vq'), secret('oebja')); }); @@ -102,7 +102,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('8 番の橙色の要素が1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.getElementById('darkorange'); expect(element).to.have.property(secret('vq'), secret('qnexbenatr')); }); @@ -111,7 +111,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('9 番の緑色の要素が1つ取得できる', function() { // 'change me!' を書き換えてください。 - var elements = 'change me!'; + var elements = document.getElementsByClassName('limegreen'); expect(elements).to.have.length(1); expect(elements[0]).to.have.property(secret('pynffAnzr'), secret('yvzrterra')); @@ -121,7 +121,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('10 番の水色の要素が2つ取得できる', function() { // 'change me!' を書き換えてください。 - var elements = 'change me!'; + var elements = document.getElementsByClassName('mediumturquoise'); expect(elements).to.have.length(2); expect(elements[0]).to.have.property(secret('pynffAnzr'), secret('zrqvhzghedhbvfr')); @@ -135,7 +135,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // // なお、11 番の青色の要素は li 要素ではありません! // よくみると、色がついているのはさらに内側の要素のようです。 - var elements = 'change me!'; + var elements = document.getElementsByTagName('p'); expect(elements).to.have.length(1); expect(elements[0]).to.have.property(secret('gntAnzr'), secret('C')); @@ -152,7 +152,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // // 'change me!' を document.querySelector('#firebrick') に // 書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('#firebrick'); expect(element).to.have.property(secret('vq'), secret('sveroevpx')); @@ -164,7 +164,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('2 番の橙色の要素を querySelector を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('#chocolate'); expect(element).to.have.property(secret('vq'), secret('pubpbyngr')); @@ -176,7 +176,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('3 番の緑色の要素を querySelector を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('.mediumseagreen'); expect(element).to.have.property(secret('pynffAnzr'), secret('zrqvhzfrnterra')); }); @@ -185,7 +185,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('4 番の水色の要素を querySelectorAll を使って2つ取得できる', function() { // 'change me!' を書き換えてください。 - var elements = 'change me!'; + var elements = document.querySelectorAll('.turquoise'); expect(elements).to.have.length(2); expect(elements[0]).to.have.property(secret('pynffAnzr'), secret('ghedhbvfr')); @@ -196,7 +196,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('5 番の青色の要素を querySelector を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('blockquote'); expect(element).to.have.property(secret('gntAnzr'), secret('OYBPXDHBGR')); }); @@ -205,7 +205,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('6 番の紫色の要素を querySelector を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('[data-js-training="blueviolet"]'); expect(element).to.have.deep.property(secret('qngnfrg.wfGenvavat'), secret('oyhrivbyrg')); @@ -220,7 +220,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // // 'change me!' を '.js-training:nth-child(2) li' // に書き換えてください。 - var selector = 'change me!'; + var selector = '.js-training:nth-child(2) li'; var element = document.querySelector(selector); expect(selector).to.not.have.string('#'); @@ -231,7 +231,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('8 番の橙色の要素を ID セレクタを使わずに1つ取得できる', function() { // 'change me!' を書き換えてください。 - var selector = 'change me!'; + var selector = '.js-training:nth-child(2) :nth-child(2)'; var element = document.querySelector(selector); expect(selector).to.not.have.string('#'); @@ -245,7 +245,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('12 番の紫色の要素を、属性セレクタと :nth-child(N) セレクタを使わずに1つ取得できる', function() { // 'change me!' を書き換えてください。 - var selector = 'change me!'; + var selector = '.js-training + .js-training > :last-child'; var element = document.querySelector(selector); expect(selector).to.not.match(/\[\s*name\s*[~\|\^\$\*]?=/); @@ -265,7 +265,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 基本的な使い方は document.querySelectorAll と同じです。 // // 'change me!' を $('#brown') に書き換えてください。 - var $element = 'change me!'; + var $element = $('#brown'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.id(secret('oebja')); @@ -275,7 +275,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('8 番の橙色の要素を jQuery を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('#darkorange'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.id(secret('qnexbenatr')); @@ -288,7 +288,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('9 番の緑色の要素を jQuery を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('.limegreen'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.class(secret('yvzrterra')); @@ -298,7 +298,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('10 番の水色の要素を jQuery を使って2つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('.mediumturquoise'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.length(2); @@ -309,7 +309,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('11 番の青色の要素を jQuery を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('p'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.length(1); @@ -320,7 +320,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('12 番の紫色の要素を jQuery を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('[data-js-training="darkorchid"]'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.length(1); @@ -334,7 +334,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('動いている寿司要素を取得する', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('x-flying-sushi-monster'); expect(element).to.have.deep.property( secret('grkgPbagrag'), '\uD83C\uDF63'); diff --git a/public/stage2/tests.js b/public/stage2/tests.js index b430dfdc..4f5dda5c 100644 --- a/public/stage2/tests.js +++ b/public/stage2/tests.js @@ -11,7 +11,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // // var element = document.getElementById('firebrick'); // element.textContent = element.textContent + element.textContent; - var element = 'change me!'; + var element = document.getElementById('firebrick'); + element.textContent = element.textContent + element.textContent; expect(element).to.have.property(secret('vq'), secret('sveroevpx')); @@ -24,7 +25,24 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は element 変数に代入してください。 - var element = 'change me!'; + var element = document.getElementById('chocolate'); + + /** + * 文字列を指定回数繰り返した文字列を返す。 + * @param {string} str 繰り返したい文字列。 + * @param {number} num 繰り返す回数。 + * @return {string} 生成された文字列。 + */ + function repeat(str, num) { + // JavaScript には文字列繰り返し演算子がないので、このように + // 文字列繰り返しをおこなう関数を定義することがよく見かけられます。 + return Array(num + 1).join(str); + + // ちなみに、上の書き方でなぜ文字列繰り返しになるのか、不思議だと + // 思いませんか?余裕があれば、どうしてこの書き方でうまくいくのか + // 考えてみてください! + } + element.textContent = repeat(element.textContent, 2); expect(element).to.have.property(secret('vq'), secret('pubpbyngr')); @@ -40,7 +58,15 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は element 変数に代入してください。 - var element = 'change me!'; + var element = document.getElementsByClassName('mediumseagreen')[0]; + + // HTMLElement#style#backgroundColor によって、背景色を指定することが + // できます。指定できる形式はいろいろありますが、今回はカラーキーワードを + // 使う問題になっています。 + // + // 色の形式いろいろ: + // https://developer.mozilla.org/ja/docs/Web/CSS/color_value + element.style.backgroundColor = 'limegreen'; expect(element).to.have.property( @@ -58,7 +84,11 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は element 変数に代入してください。 - var element = 'change me!'; + var element = document.getElementsByClassName('turquoise')[0]; + + // HTMLElement#style#opacity によって、要素の不透明度を指定することが + // できます。 + element.style.opacity = 0.5; expect(element).to.have.property( @@ -76,7 +106,11 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は element 変数に代入してください。 - var element = 'change me!'; + var element = document.getElementsByTagName('blockquote')[0]; + + // transform に指定できる要素はいろいろありますが、今回は rotate を使うの + // がよさそうです。 + element.style.transform = 'rotate(10deg)'; expect(element).to.have.property( @@ -95,10 +129,34 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は element 変数に代入してください。 // - // なお、上に 20px 移動させる方法は複数ありますが、今回は top 属性を + // なお、上に 20px 移動させる方法は複数ありますが、今回は top プロパティを // 使う方法を使ってください。 - var element = 'change me!'; + var element = document.querySelector('[data-js-training="blueviolet"]'); + + // top プロパティの指定は、数値ではないので注意が必要です。 + element.style.top = '-20px'; + + // しかし、上の top 指定だけだと、要素が動いてくれません! + // なぜでしょうか?そういうときは、まず MDN で検索してみましょう。 + // + // top - CSS | MDN + // https://developer.mozilla.org/ja/docs/Web/CSS/top + // + // ここには下のように書かれています。 + // + // > CSS の top プロパティは、位置指定された要素 (positioned elements) の + // > 位置を定義します。位置指定されていない要素には効力を持ちません。 + // + // なるほど、position を設定していなかったからかもしれません。 + // + // > 相対位置指定要素( position が relative である要素)では、 + // > 通常位置からの下方への移動量を定義します。 + // + // position が relative であれば、下への移動量で指定できるということですね。 + // ということで、relative を指定します。 + element.style.position = 'relative'; + // 動きました! expect(element).to.have.deep.property( secret('qngnfrg.wfGenvavat'), secret('oyhrivbyrg')); @@ -127,7 +185,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // // var $element = $('#brown'); // $element.text($element.text() + $element.text()); - var $element = 'change me!'; + var $element = $('#brown'); + $element.text($element.text() + $element.text()); expect($element).to.be.instanceof(jQuery); @@ -140,7 +199,14 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は $element 変数に代入してください。 - var $element = 'change me!'; + var $element = $('#darkorange'); + + // またまた登場です! + function repeat(str, num) { + return Array(num + 1).join(str); + } + + $element.text(repeat($element.text(), 2)); expect($element).to.be.instanceof(jQuery); @@ -156,7 +222,13 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は $element 変数に代入してください。 - var $element = 'change me!'; + + // jQuery#css によって、style 属性の値を操作することができます。 + // 指定の方法はいろいろあります: + // + // - $('.limegreen').css('backgroundColor', 'mediumseagreen'); + // - $('.limegreen').css('background-color', 'mediumseagreen'); + var $element = $('.limegreen').css({ backgroundColor: 'mediumseagreen' }); expect($element).to.be.instanceof(jQuery); @@ -173,7 +245,7 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は $element 変数に代入してください。 - var $element = 'change me!'; + var $element = $('.mediumturquoise').css({ opacity: 0.5 }); expect($element).to.be.instanceof(jQuery); @@ -186,7 +258,7 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は $element 変数に代入してください。 - var $element = 'change me!'; + var $element = $('p').css({ transform: 'rotate(10deg)' }); expect($element).to.be.instanceof(jQuery); @@ -205,7 +277,10 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // // なお、上に 20px 移動させる方法は複数ありますが、今回は top 属性を // 使う方法を使ってください。 - var $element = 'change me!'; + var $element = $('[data-js-training="darkorchid"]').css({ + top: '-20px', + position: 'relative' + }); expect($element).to.be.instanceof(jQuery); diff --git a/public/stage3/tests.js b/public/stage3/tests.js index fa3cb6f2..94205fe2 100644 --- a/public/stage3/tests.js +++ b/public/stage3/tests.js @@ -12,6 +12,9 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // var ghost = document.querySelector('.firebrick-ghost'); // element.removeChild(ghost); + var element = document.querySelector('#firebrick'); + var ghost = document.querySelector('.firebrick-ghost'); + element.removeChild(ghost); var firebrick = document.getElementById('firebrick'); expect(firebrick.childNodes.length).to.equal(1); @@ -23,6 +26,9 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // ここにコードを記述してください。 + var element = document.querySelector('#chocolate'); + var ghost = element.querySelector('.chocolate-space-invader'); + element.removeChild(ghost); var darkorange = document.getElementById('chocolate'); expect(darkorange.childNodes.length).to.equal(1); @@ -34,6 +40,27 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // ここにコードを記述してください。 + var element = document.querySelector('.mediumseagreen'); + var ghosts = element.querySelectorAll('.mediumseagreen-ghosts'); + var ghost; + + // 残念なことに、querySelectorAll の返すオブジェクトは配列ではないため、 + // Array#forEach が使えません。代わりに、for ループを使っています。 + for (var idx = 0, len = ghosts.length; idx < len; idx++) { + ghost = ghosts[idx]; + element.removeChild(ghost); + } + + // JavaScript に慣れた人であれば、いったん配列に変換してから、 + // forEach を使うことが多いようです。また、lodash や underscore といった + // ユーティリティライブラリは、配列のようなオブジェクトでも使える + // forEach 関数を提供しているので、そちらを利用することもあります。 + // + // function arrayFrom(arrayLike) { + // return Array.prototype.slice.call(arrayLike); + // } + // + // arrayFrom(ghosts).forEach(element.removeChild.bind(element)); var darkorange = document.querySelector('.mediumseagreen'); expect(darkorange).to.have.property('textContent', '3\uD83C\uDF3F'); @@ -46,6 +73,9 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // 上の elementToAdd を追加するコードをここに記述してください。 + // Node#appendChild メソッドをつかって、要素を最後に追加します。 + document.querySelector('.turquoise').appendChild(elementToAdd); + var turquoise = document.querySelector('.turquoise'); expect(turquoise.childNodes.length).to.equal(2); @@ -60,6 +90,30 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // 上の elementToAdd を、5 番の青色の要素の最初に追加するコードを // ここに記述してください。 + var element = document.querySelector('blockquote'); + + // Node#appendChild だと要素の最後に追加されてしまうので、特定の要素の前に + // 要素を追加する Node#insertBefore メソッドを使います。 + // + // ここではまるのは、insertBefore には、追加する要素と基準となる要素の2つを + // 引数として与えないといけないということです。しかし、blockquote 要素には + // 基準となる要素がなさそうにみえます... + // + // そこで、Node の子要素を保持している Node#childNodes を見てみましょう。 + // + // console.log(element.childNodes.length) + // + // どうやら、1つだけ子要素を持っているようです。 + // 中身を見てみましょう。 + // + // console.log(element.childNodes[0]); + // + // なにやら文字列?らしきものが入っています(element.childNodes[0].constructor.name + // で調べるとわかりますが Text オブジェクトです)。 + // つまり、基準となる要素にはこの Text オブジェクトを指定できそうです! + // + // なお、element.childNodes[0] は element.firstChild は同じ意味です。 + element.insertBefore(elementToAdd, element.firstChild); var blockquote = document.querySelector('blockquote'); @@ -79,6 +133,7 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // ここに以下のコードを記述してください。 // // $('.brown-ghost').remove(); + $('.brown-ghost').remove(); var $brown = $('#brown'); @@ -90,6 +145,7 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で it('7 番の要素からインベーダー要素を除去する', function() { // ここにコードを記述してください。 + $('.darkorange-space-invader').remove(); var $darkorange = $('#darkorange'); @@ -105,6 +161,9 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // ここにコードを記述してください。 + // DOM を直接扱うのに対して、非常に簡潔な表現が利用できています! + $('.limegreen-ghosts').remove(); + var $limegreen = $('.limegreen'); expect($limegreen).to.have.text('8\uD83C\uDF3F'); @@ -115,6 +174,7 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で var $elementToAdd = $('\uD83D\uDC2C'); // 上の $elementToAdd を追加するコードをここに記述してください。 + $('.mediumturquoise').append($elementToAdd); var $mediumturquoise = $('.mediumturquoise'); @@ -128,6 +188,9 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // 上の $elementToAdd を追加するコードをここに記述してください。 + // insertBefore ではなく、prepend が使えます。 + $('p').prepend($elementToAdd); + var $p = $('p'); expect($p.children()).to.have.length(1); diff --git a/public/stage4/tests.js b/public/stage4/tests.js index 599536b6..40ee36d4 100644 --- a/public/stage4/tests.js +++ b/public/stage4/tests.js @@ -24,6 +24,11 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun // // ここに上記のどちらかのコードを記述してください。 + var element = document.getElementById('firebrick'); + element.addEventListener('click', function() { + element.textContent = Number(element.textContent) + 1; + }); + var firebrick = document.getElementById('firebrick'); firebrick.dispatchEvent(createClickEvent()); @@ -38,6 +43,11 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun // ここにコードを記述してください。 + var element = document.getElementById('chocolate'); + element.addEventListener('click', function() { + element.textContent = Number(element.textContent) - 1; + }); + var chocolate = document.getElementById('chocolate'); chocolate.dispatchEvent(createClickEvent()); @@ -52,6 +62,16 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun // ここにコードを記述してください。 + var element = document.getElementsByClassName('mediumseagreen')[0]; + + // クリック前の角度を保存しておくと、rotate の中から数字を取り出さなくて + // すむので、楽に書くことができます。 + var angleDegree = 0; + element.addEventListener('click', function() { + angleDegree += 10; + element.style.transform = 'rotate( ' + angleDegree + 'deg)'; + }); + var mediumseagreen = document.querySelector('.mediumseagreen'); mediumseagreen.dispatchEvent(createClickEvent()); @@ -67,6 +87,14 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun it('4 番の要素を入力された角度に回転できる', function() { // ここにコードを記述してください。 + var element = document.getElementsByClassName('turquoise')[0]; + var input = element.getElementsByTagName('input')[0]; + + // change イベントを使います。 + input.addEventListener('change', function() { + var angleDegree = input.value; + element.style.transform = 'rotate( ' + angleDegree + 'deg)'; + }); var turquoise = document.querySelector('.turquoise'); @@ -93,9 +121,36 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun // なお、expect(steelblue).to.be.null は上記のテストの要件を満たして // いないので、正解ではありません。 - var steelblue = document.querySelector('.steelblue'); - expect(steelblue).to.have.property('textContent', '5 \uD83D\uDC33'); - done(); + + // この問題は、JavaScript の実行タイミングによっておきています。 + // 実は、この JavaScript が実行される時点では、また 5 番の要素の + // DOM が作成されていないのです! + // + // 開発ツールで DOM の構造をみてみると、tests.js を読み込む script タグの + // 後に、5 番目の要素が配置されています。このような配置のとき、下のような + // 順番で処理が実行されています。 + // + // 1.