東京の会社辞めて地方で生きるわ。

勢いで会社を辞めて縁のない地方で生きることはできるのか

JavaScriptメモ

プロパティとメソッド

プロパティは()はない

繰り返しのfor文とwhile文の違い

繰り返す回数が決まってるときはfor、決まってないときはwhile

オブジェクトの意味

①window.alert、console.logなどのwindowやconsoleのこと。

javascriptの基本文法は
console.log('テスト')

consoleはオブジェクト
logはメソッド
()の中のテストはパラメータ

オブジェクトは基本文法の「●●は××しなさい」でいえば●●にあたる部分。

②「複数のプロパティを持つデータのまとまり」

var jsbook = {title: 'javascript入門', price:2500, stock: 3}

上記のjsbookオブジェクトはプロパティしかないが、プロパティのデータにはファンクションを保存することができる

var obj = {
  addTax : function(num) {
    return num * 1.08;
  }
};

上記のようにプロパティのデータがファンクションのとき、そのプロパティのことを特別にメソッドという。
ここらへんは「javascriptオブジェクト指向プログラミング」という知識とテクニックが必要

③Dateオブジェクト

Dateオブジェクトを使うときは最初に以下のコードを描いて初期化する必要がある。

var now = new Date();

newはオブジェクトを初期化するためのキーワード。
なお初期化の際()内にパラメータを含めない場合、Dateオブジェクトは現在日時を記憶した状態で初期化される。
ちなみに「現在日時を記憶した状態」とは、
●「日時を出力しなさい」と命令したら、現在日時を出力する
●「10日後が何日か出力しなさい」と命令したら、現在日時から10日後の日付を出力する。
というように、現在日時を「基準日」として使っている。
つまり、初期化されたDateオブジェクトが計算の基準日となる日時を記憶しているからこそ、日時の出力や計算ができる。

④オブジェクトには初期化するものとしないものがある

●複数のオブジェクトを作れるオブジェクトは初期化する
●複数のオブジェクトを作れないオブジェクトは初期化しない
詳しくは「確かな力が身につく」JavaScript超入門」のP165を参照。


無名関数(ファンクションを変数に代入)

var total = function(price){
  var tax = 0.08;
  return price + price * tax;

}

イベント基本構文

document.getElementById('form').onsubmit = function(){

};

return falseの意味

イベントで実行されるファンクションに「return false;」が出てきたら、htmlの基本動作をキャンセルしていると解釈する。
例だと送信ボタンを押したらページが遷移(ページ再読み込み)するがそれをキャンセルしたりできる。

画像のプリロード

var images = ['images/image1.jpg', 'images/image2.jpg', 'images/image3.jpg'];
var current = 0;
var pageNum = function(){
  document.getElementById('page').textContent = (current + 1) + '/' + images/length;
}

var changeImage = function(num){
  if(current + num >= 0 && current + num < images.length){
    current += num;
    document.getElementById('main_image').src = images[current];
    pagenum();

  }
};
// プリロードのコード start
var preloadImage = function(path){
  var imgTag = document.createElement('img');
  imgTag.src = path;
}

for(var i = 0;i < images.length; i++){
  preloadImage(images[i]);
}
//プリロードのコード end

pageNum();

document.getElementById('prev').onclick = function(){
  changeImage(-1);
};

document.getElementById('next').onclick = function(){
  changeImage(1);
};
                                                                                                                                                                • -

変数宣言

let msg;

変数の重複を許可しない。varは許可する(上書きする)

定数

入れ物と中身がワンセットで途中で中身を変更できない入れ物のことを定数という。

var price = 100;
console.log(price * 1.08);
const TAX = 1.08;
var price = 100;
console.log(price * TAX);

データ型

①基本型

●数値型
●文字列型
●真偽型 true/false
●シンボル型
●特殊型(値が空、未定義であることを表す)

②参照型

●配列 array
●オブジェクト object
●関数 function

リテラル

リテラルとは、データ型に格納できる値そのもの、また、値の表現方法のこと。
・数値リテラル
・文字列リテラル

テンプレート文字列

・文字列への変数
・複数行にまたがる文字れ宇
が可能。

let name = '鈴木';
let str = `こんにちは、${name}さん。
今日も良い天気ですね!`;
console.log(str);

配列リテラル

配列リテラルは、以下のようにカンマ区切りの値をブラケット[]でくくった形式で表現します。

['JavaScript', 'Ajax', 'ASP.NET'];
console.log(data[0]);

オブジェクトリテラル

オブジェクトとは、名前をキーにアクセスできる配列。ハッシュ、連想配列などよばれる。
配列内の個々のデータを「要素」と呼んでいたのに対して、オブジェクト内の個々のデータはプロパティと呼ぶ。
プロパティには文字列や数値などの情報はもちろん、関数(手続き)を格納することもできる。
関数が格納されたプロパティのことは、特別にメソッドと呼ぶ。

var obj = {x:1, y:2, z:3};
console.log(obj.x); // ドット演算子
console.log(['x']);  // ブラケット構文

関数リテラル

関数とは「なにかしらの入力値(引数)を与えられることによって、あらかじめ決められた処理を行い、その結果(戻り値)を返すしくみ」のことをいう。

未定義値(undefined)

未定義値はある変数の値が定義されていないことを表す値で、以下のようなケースで返される。

・ある変数が宣言済みであるものの値を与えられていない
・未定義のプロパティを参照しようとした
・関数で値が返されなかった

var x; 
var obj = {a:12345};
console.log(x);
console.log(obj.b);
// 結果:2つともunderfined

ヌル(null)

該当する値がないことを意味する。
意図した空を表すにはnull、そうでなければundefined

インクリメント演算子(++)とデクリメント演算子(--)

インクリメント/デクリメント演算子は、オペランドに対して1を加算/減算します。つまり、以下の記法はそれぞれ等価です。


x++ → x = x + 1

x-- → x = x - 1

var x = 3;
var y = x++;
console.log(x); // 結果:4
console.log(y); // 結果:3

var x = 3;
var y = ++x;
console.log(x); // 結果:4
console.log(y); // 結果:4

function命令で関数を定義

function getTriangle(base, height){
  return base * height / 2;
}

console.log('三角形の面積:' + getTriangle(5, 2)); // 結果:5

関数リテラル表現で関数を定義

var getTriangle = function(base, height){
  return base * height / 2;
};

console.log('三角形の面積:' + getTriangle(5,2));

function命令:関数getTriangleを直接定義
これは関数を呼び出した後に
function命令を描いてもチャンと動く


関数リテラル:「function(base,height){...}」と名前のない関数を定義したうえで、変数getTriangleに格納している
このように関数リテラルは宣言した時点では名前を持たないことから匿名関数、無名関数と呼ばれる。
関数リテラルは関数を呼び出したあとに
関数リテラルを描いたらエラーがおこる

仮引数のスコープ 基本型と参照型の違いに注意

仮引数とは「呼び出し元から関数に渡された値を受け取るための変数」直上の例ならbase,heightが仮引数にあたる。


【基本型の場合】

var value = 10;

function decrementValue(value){
  value--;
  return value;
}

console.log(decrementValue(100));  // 結果:99
console.log(value); // 結果:10

【参照型】

var value = [1,2,4,8,16];
function deleteElement(value){
  value.pop();
  return value;
}

console.log(deleteElement(value)); // 結果:[1,2,4,8]
console.log(value); // 結果:[1,2,4,8]

複数の戻り値を個別の変数代入

「関数から複数の値を返したい」というケースはよくある。しかし、return命令で「return x, y;」のように複数の値を返すことはできません。この場合には、配列/オブジェクトとして値を一つにまとめたうえで返す必要がある

function getMaxMin(...nums){
  return [Math.max(...nums), Math.min(...nums)];
}

let result = getMaxMin(10,35,-5,78,0);
console.log(result);

let [max, min] = getMaxMin(10,35,-5,78,0);
console.log(max);
console.log(min);

再帰関数

再帰関数とは、ある関数が自分自身を呼び出すこと、または、そのような関数のこと。再帰関数を利用することで、たとえば階乗計算のように、同種の手続きを何度も呼び出すような処理を、よりコンパクトに表現できる。

function factorial(n){
  if (n != 0){ return n * factorial(n - 1); }
  return 1;
}

console.log(factorial(5));

クラス定義

最もシンプルなクラスを定義は以下。

var Member = function(){};

「変数Memberに対して、空の関数リテラルを代入しているだけではないか」と思われるかもしれないが、そのとおり、これがJavaScriptのクラスになる。

このMemberクラスは以下のようにnew演算子インスタンス化できる。
JavaScriptでは関数(funtionオブジェクト)にクラスとしての役割を与えている。

var mem = new Member();
 

コンストラクターで初期化する

コンストラクターとは「インスタンス(オブジェクト)」を生成する際に、オブジェクトを初期化する処理を記述するための特殊なメソッド(関数)」のこと。上で定義したMember関数もまた、「new演算子によって呼び出され、オブジェクトを生成する」という意味で、厳密にはクラスというより、コンストラクターと呼ぶのが正しい。
コンストラクターの名前は、普通の関数と区別するために大文字で始めるのが一般的。

var Member = function(firstName, lastName){
  this.firstName;
  this.lastName;
  this.getName = function(){
    return this.lastName + ' ' + this.firstName;
  }
};

var mem = new Member('太郎', 山田');
console.log(mem.getName());  // 結果:山田 太郎

上はコンストラクターに初期化処理したコード。
上のコードで注目すべきは、this。thisキーワードは、コンストラクターによって生成されるインスタンス(つまり自分自身)を表すもの。thisキーワードに対して変数を指定することで、インスタンスのプロパティを設定できる。

プロパティの定義
this.プロパティ名 = 値;

またプロパティには、文字列や整数、日付などだけではなく、関数オブジェクト(関数リテラル)を指定できる点にも注目。JavaScriptにおいては、厳密にはメソッドという独立した概念はなく、
値が関数オブジェクトであるプロパティがメソッドとみなされる。

文脈によって中身が変化する変数 this

場所 thisの参照先
トップレベル(関数の外) グローバルオブジェクト
関数 グローバルオブジェクト(Strictモードではunderfined)
call/applyメソッド 引数で指定されたオブジェクト
イベントリスナー イベントの発生元
コンストラクター 生成したインスタンス
メソッド 呼び出し元のオブジェクト(=レシーバーオブジェクト)


メソッドはプロトタイプで宣言する prototypeプロパティ

インスタンス共通のメソッドを定義するには、少なくともコンストラクターでメソッドを定義する必要があることがわかった。しかし、実はコンストラクターによるメソッドの追加には、

メソッドの数に比例して、無駄なメモリを消費する

という問題がある。
そこでJavascriptでは、オブジェクトのメンバを追加するためにprototypeというプロパティを用意している。

// クラス・コンストラクタ作成
var Member = function(firstName, lastName){
  this.firstName = firstName;
  this.lastName = lastName;
};

// プロトタイプでメソッド追加
Member.prototype.getName = function(){
  return this.lastName + '' + this.firstName;
};

// インスタンス生成
var mem = new Member('太郎', '山田');
console.log(mem.getName());

プロパティの宣言はコンストラクタで。
メソッドの宣言はプロトタイプで。


オブジェクトリテラルでプロトタイプを定義

上の例はどっと演算子を使って、プロトタイプにメンバーを追加してきた。
しかし、メンバー数が多くなってきた場合、コードが冗長になる。
このままだと毎回「Member.prototype.~」という記述を繰り返すのは面倒で、そもそもオブジェクト名(ここではMember)が変更になった場合に、すべての定義個所を書き換えなければならないのは、うれしくない。
下記のように書けば楽。

var Member = function(firstName, lastName){
  this.firstName = firstName;
  this.lastName = lastName;
};

Member.prototype = {
  getName : function(){
    return this.lastName + ' ' + this.firstName;
  },
  toString : function(){
    return this.lastName + this.firstName;
  }
};

このように、オブジェクトリテラルを利用することで、

・「Member.prototype.~」のような記述を最小限に抑えられる
・結果、オブジェクト名に変更があった場合にも影響個所を限定できる
・同一オブジェクトのメンバー定義がひとつのブロックに収められているため、コードの可読性が向上する


プロトタイプチェーン(オブジェクトの継承)

オブジェクト指向言語を理解するうえで、重要な概念のひとつが継承。継承とは、もとになるオブジェクト(クラス)の機能を引き継いで、新たなクラスを定義する機能のこと。

var animal = function() {};

Animal.prototype = {
  walk : function(){
    console.log('トコトコ...')
  }
}

var Dog = function(){
  Animal.call(this);
};

Dog.prototype = new Animal();  // ①
Dog.prototype.bark = function(){
  console.log('ワンワン!');
}

var d = new Dog();
d.walk();  // 結果:トコトコ...
d.bark();  // 結果:ワンワン!

上のコードで注目するのは①の部分。Dogオブジェクトのプロトタイプ(Dog.prototype)としてAnimalオブジェクトのインスタンスをセットしていることが確認できる。これによって、DogオブジェクトのインスタンスからAnimalオブジェクトで定義されたwalkメソッドを呼び出せるようになる。

継承関係は動的に変更可能

var Animal = function(){};

Animal.prototype = {
  walk : function() {
    console.log(トコトコ...)
  }
}

var SuperAnimal = function() {};
SuperAnimal.prototype = {
  walk : function(){
    console.log('ダダダダダ!');
  }
};

var Dog = function(){};
Dog.prototype = new Animal(); // Animalオブジェクトを継承
var d1 = new Dog();
d1.walk(); // 結果:トコトコ...

Dog.protype = new SuperAnimal();
var d2 = new Dog();
d2.walk(); // 結果:ダダダダダ!
d1.walk(); // 結果:トコトコ...

プライベートメンバーを定義

プライベートメンバーとは、クラス内部のメソッドからのみ呼び出すことのできるプロパティ/メソッドのこと。クラス内部でだけ使用する情報や処理を定義したい場合には、プライベートメンバーとして定義しておくことで、不用意に外部からアクセスされる心配がなくなる。

【例】

function Triangle(){
  // プライベートプロパティの定義(底辺/高さを保持)
  var _base;
  var _height;
  // プライベートメソッドの定義(引数が正の数値であるかチェック)
  var _checkArgs = function(val){
    return (typeof val === 'number' && val > 0);
  }

  // プライベートメンバーにアクセスするためのメソッドを定義
  this.setBase = function(base){
    if (_checkArgs(base)) { _base = base; }
  }
  this.getBase = function() { return _base; }

  this.setHeight = function(height) {
    if (_checkArgs(height)) { _height = height; }
  }
  this.getHeight = function(){ return _height; }

}

// プライベートメンバーにアクセスしない普通のメソッドを定義
Triangle.prototype.getArea = function(){
  return this.getBase() * this.getHeight() / 2;
}

var t = new Triangle();
t._base = 10;
t.height = 2;
console.log('三角形の面積:' + t.getArea());  // 結果:NaN

t.setBase(10);
t.setHeight(2);
console.log('三角形の底辺:' + t.getBase());  // 結果:10
console.log('三角形の高さ:' + t.getHeight());  // 結果:2
console.log('三角形の面積:' + t.getArea());  // 結果:10

名前空間 / パッケージを生成する

クラスの数が多くなってくると、「クラス名がライブラリ同士、あるいは、ライブラリとライブラリを利用しているアプリとで競合する」というケースがでてくる。
なので名前空間の配下にクラスライブラリをまとめる。

var Wings = Wings || {};  // ①

Wings.Member = function(firstName, lastName){
  this.firstName = firstName;
  this.lastName = lastName;
};  // ②

Wings.Member.prototype = {
  getName : function(){
    return this.lastName + ' ' + this.firstName;
  }
};

var mem = new Wings.Member('太郎', '山田');  // ③
console.log(mem.getName());

名前空間を定義するにはただ単に「空のオブジェクトを生成する」だけ。ここでは①でWings名前空間を定義している。

var Wings = {};

これだけでも動作はするが、「Wings || {}」とすることによって、「Wings」が未定義の場合にだけ新たな名前空間を作成する」という意味になる。
あとは、Wings名前空間(オブジェクト)に対して、性的プロパティを追加するのと同じ要領で、配下に置きたいクラス(コンストラクタ)を定義する。(②)
これによってWings名前空間の配下に属するMemberクラスが定義できた。
名前空間配下のクラスをインスタンス化する場合には、名前空間も含んだ名前としてクラス名を指定する必要がある。(③)

ES2015のオブジェクト指向構文

クラスを定義する class命令

以下のコードはfirstName/lastNameプロパティ、getNameメソッドを持つMemberクラスを定義。

class Member {
  // コンストラクター
  constructor(firstName, lastName){
    this.firstName = firstName;
    this.lastName = lastName;
  }

  // メソッド
  getName(){
    return this.lastName + this.firstName;
  }
}

let m = new Member('太郎', '山田');
console.log(m.getName()); // 結果:山田太郎

class命令の構文は以下

class クラス名{
  ...コンストラクタの定義
  ...プロパティの定義
  ...メソッドの定義
}

コンストラクタ/メソッドの定義

メソッド名(引数, ...){
  ...メソッドの本体...
}

要素ノード取得メソッド

●getElementById
●getElementsByTagName(最初のひとつだけではなく該当するタグすべて取得)
●getElementsByName(inputやselectタグなどフォーム要素へのアクセスで利用。)
●getElementsByClassName(最初のひとつだけではなく該当するクラスが付与された要素すべて取得)
getElementsBYClassNameの引数には「clazz1 clazz2」のように空白区切りで(カンマではない)複数のクラス名を列記できる。この場合、class属性としてclazz1、clazz2双方が指定された要素だけを検索。

●querySelector/querySelectorAll(cssセレクタでノード取得できて超便利。最初のひとつだけを取り出したい時はquerySelectorでOK/該当するセレクタすべて取得はquerySelectorAll)
このquerySelectorは高機能なメソッドだが、getElementByIdやgetElementsByxxxに比べると低速。
一般的には
・特定のid値、class属性などで要素を検索できる場合はgetxxxメソッド
・より複雑な検索条件で検索したい場合はqueryxxxメソッド
でやる。

イベント

●イベントに対応してその処理内容を定義するコードのかたまり(関数)のことをイベントハンドラ・イベントリスナーという。

mouseover / mouseoutと mouseenter / mouseleaveの違い

mouseenter / mouseleaveイベントが、あくまで対象の要素の出入りに際して発生するのに対して、mouseover / mouseoutは内側の要素に出入りしたときにも発生する。

イベントハンドラー/イベントリスナーを定義する

①タグ内の属性として宣言する
②要素オブジェクトのプロパティとして宣言する
③addEventListenerメソッドを使って宣言する

まずは、③を利用すべきだが、①②も手軽でよく使われる
ちなみに、①②で宣言されたイベント処理を「イベントハンドラー」、③で宣言されたものを「イベントリスナー」と呼ぶ。

①タグ内の属性として宣言する

<input type="button" value="ダイアログ表示" onclick="btn_click()" />
function btn_click(){
  window.alert('ボタンがクリックされた');
}

②要素オブジェクトのプロパティとして宣言する

イベントハンドラの呼び出しだけであるとはいえ、本来、レイアウトを定義すべきHTMLの中にjsのコードを混在させるのは好ましくない。そこでこのやり方

<input id="btn" type="button" value="ダイアログ表示" />
window.onload = function(){
  document.getElementById('btn').onclick = function(){
    window.alert('ボタンがクリックされた');
  };
};

③addEventListenerメソッドを使って宣言する

<input id="btn" type="button" value="ダイアログ表示" />
document.addEventListener('DOMContentLoaded', function(){
  document.getElementById('btn').addEventListener('click', function(){
    window.alert('ボタンがクリックされました。');
  }, false);

}, false);

DOMContentLoadedイベントリスナーは、onloadイベントハンドラと同じく、「ページがロードされたタイミングで処理を実行しなさい」という意味。
ただし、onloadとは実行タイミングが少し異なる。

・onload: コンテンツ本体とすべての画像がロードされたところで実行
・DOMContentLoaded: コンテンツ本体がロードされたところで実行(画像のロードを待たない)

たいがいの処理は、画像のロードをを待つ必要はないはずなので、DOMContentLoadedイベントリスナーを利用することでスクリプトの開始タイミングを早められる。画像にかかわる処理があるなど、特別な理由がないかぎり、

ページの初期化処理は、DOMContentLoadedで表すのが基本

イベントリスナー・イベントハンドラーを削除する

イベントハンドラーの削除

イベントハンドラを削除するにはonxxxメソッドに対してnull値を設定。

<form>
  <input id="btn" type="button" value="ダイアログ表示"> 
</form>
window.onload = function(){
  var btn = document.getElementById('btn');
  
  // イベントハンドラを登録
  btn.onclick = function(){
    window.alert('こんにちは、世界!');
  };

  // イベントハンドラを削除
  btn.onclick = null;
};

イベントリスナーの削除

イベントリスナーを削除するにはremoveEventListenerメソッドを利用。

elem.removeEventListener(type, listener, capture)
  elem:要素オブジェクト type:イベントの種類 listener: 削除するイベントリスナー
  capture: イベントの伝播方向(デフォルトはfalse)

【例】

<form>
  <input id="btn" type="button" value="ダイアログ表示"> 
</form>
document.addEventListener('DOMContentLoaded', function(){
  var btn = document.getElementById('btn');
  var listener = function(){
    window.alert('こんにちは、世界!');
  };

  // イベントリスナー登録
  btn,addEventListener('click', listener, false);

  // イベントリスナー破棄
  btn.removeEventListener('click', listener, false);
}, false);

};

イベントにかかわる情報を取得 イベントオブジェクト

イベントリスナ/イベントハンドラは引数としてイベントオブジェクトと呼ばれるオブジェクトを受けとる。イベントリスナ・イベントハンドラ配下では、イベントオブジェクトのプロパティにアクセスすることで、イベント発生時の様々な情報にアクセスできる。

<form>
  <input id="btn" type="button" value="クリック" />
</form>
document.addEventListener('DOMContentLoaded', function(){
  document.getElementById('btn').addEvenListener('click', function(e){
    var target = e.target;
    console.log('発生元:' + target.nodeName + '/' + target.id);
    console.log('種類:' + e.type);
  }, false);
}, false);

●イベント発生時のマウス情報を取得する
(イベントオブジェクトにおける座標関連プロパティ)
screenX / screenY : スクリーン上の座標
pageX / pageY : ページ上の座標
clientX / clientY : 表示領域上の座標
offsetX / offsetY : 要素領域上の座標


イベント処理をキャンセルする

イベントオブジェクトのstopPropagation / stopImmediatePropagation / preventDefaultメソッドを利用することでイベント処理を途中でキャンセルできる。

イベントの伝播
<div id="outer">
  <p>outer要素</p>
  <a id="inner" href="aaaaaa">inner要素</a>
</div>
document.addEventListener('DOMContentLoaded', funciton(){
  // <a id="inner">要素のclickイベントリスナー
  document.getElementById('inner').addEventListener('click', function(e){
    window.alert('#innerリスナーが発生しました');
  }, false);

  document.getElementById('inner').addEventListener('click', function(e){
    window.alert('#innerリスナー2が発生しました');
  }, false);

  document.getElementById('outer').addEventListener('click', function(e){
    window.alert('#outerリスナーが発生しました');
  }, false);

}, false);

上のコードで、innerをクリックすると以下のような順序で処理が実行。イベントの発生源を起点として。上位ノードへ向かって順にイベントリスナが実行されている。

1.ダイアログ表示(#innerリスナーが発生しました)
2.ダイアログ表示(#innerリスナー2が発生しました)
3.ダイアログ表示(#outerリスナーが発生しました)
4.リンクによってページ移動

この順序は、addEventListenerメソッドの第3引数で変更することもできる。falseのところをtrueとすると、

1.ダイアログ表示(#outerリスナーが発生しました)
2.ダイアログ表示(#innerリスナーが発生しました)
3.ダイアログ表示(#innerリスナー2が発生しました)
4.リンクによってページ移動

というように、上位ノードからイベントの発生源に向かって、イベントリスナが実行される。


イベントの伝播をキャンセル
document.addEventListener('DOMContentLoaded', funciton(){
  // <a id="inner">要素のclickイベントリスナー
  document.getElementById('inner').addEventListener('click', function(e){
    window.alert('#innerリスナーが発生しました');
    e.stopPropagation();
  }, false);

  document.getElementById('inner').addEventListener('click', function(e){
    window.alert('#innerリスナー2が発生しました');
  }, false);

  document.getElementById('outer').addEventListener('click', function(e){
    window.alert('#outerリスナーが発生しました');
  }, false);

}, false);

この上のコードだと、リンクをクリックすると

1.ダイアログ表示(#innerリスナーが発生しました)
2.ダイアログ表示(#innerリスナー2が発生しました)
3.リンクによってページ移動

親ノードへのバブリングがキャンセルされる。


イベントの伝播をただちにキャンセル

stopPropagationメソッドが上位/下位要素への伝播をキャンセルするのに対して、その場でキャンセルする(=同じ要素に登録されたリスナーも実行しないようにする)には、stopImmediatePropagationメソッドを利用。
上の「e.stopPropagation();」を「e.stopImmediatePropagation」に変えると、

1.ダイアログ表示(#innerリスナーが発生しました)
2.リンクによってページ移動

となる。


イベント本来の挙動をキャンセルする

イベント本来の挙動とはaタグをおすとページを移動する、とかのこと。これをキャンセルするときは、e.preventDefault();を使用。
上の「e.stopPropagation();」を「e.preventDefault();」に変えると、

1.ダイアログ表示(#innerリスナーが発生しました)
2.ダイアログ表示(#innerリスナー2が発生しました)
3.ダイアログ表示(#outerリスナーが発生しました)

となり、ページを移動しない。

イベントハンドラーでキャンセルしたい

イベントハンドラーでは、戻り値としてfalseを返すことで、イベント本来の挙動をキャンセルできる。例えば、以下はcontextmenuイベントをキャンセルすることで、コンテキストメニューを表示できないようにする例。

<div oncontextmenu="return false;">...</div>

キャンセル系メソッドまとめ

メソッド 伝播 別のリスナー デフォルトの挙動
stopPropagation 停止 - -
stopImmediatePropagation 停止 停止 -
preventDefault - - 停止

つまり、以降のイベント伝播、標準の挙動をすべてキャンセルするには、stopImmediatePropagation / preventdefaultメソッドを呼び出せばいい。

setInterval / setTimeout メソッド

setInteval : 決められた時間間隔で繰り返し処理を実行する
setTimeout : 指定された時間が経過したところで1回だけ処理を実行する

<input id="btn" type="button" value=" タイマー停止" />
<div id="result"></div>
document.addEventListener('DOMContentLoaded', function(){
  // タイマーを設置
  var timer = window.setInterval(
  // 現在の時刻を<div id="result">要素に表示(5000ミリ秒ごとに更新)
    function(){
      var dat = new Date();
      document.getElementById('result').textContent = dat.toLocaleTimeString();
    }, 5000);
  
    // ボタンクリック時にタイマー処理を中止
    document.getElementById('btn').addEventListener('click', function(){
      window.clearInterval(timer);    
  
  
  },false);                       
}, false);

表示ページのアドレス情報を取得/捜査する locationオブジェクト

以下はセレクトボックスで選択したら自動的にそのページに移動するコード。

<form>
  <label for="isbn">書籍:</label>
  <select id="isbn" name="isbn">
    <option value="">-- 書籍名を選択してください --</option>
    <option value="978-4-7741-8030-4">書籍1</option>
    <option value="978-4-7741-8030-5">書籍2</option>
    <option value="978-4-7741-8030-6">書籍3</option>
    <option value="978-4-7741-8030-7">書籍4</option>
    <option value="978-4-7741-8030-8">書籍5</option>    
  </select>
</form>
document.addEventListener('DOMContentLoaded', function(){
  document.getElementById('isbn').addEventListener('change', function(){
    location.href="http://www.test/test" + this.value;
  },false);
},false);

JavaScriptによる操作をブラウザの履歴に残す pushStateメソッド

JavaScriptでページを更新した場合、そのままではページの状態を保持することができない。例えばボタンをクリックしてJavascriptでページを更新した後、クリック前の状態に戻したいと思い「もどる」ボタンを押すと、そのまま1つ前のページに戻ってしまう。

そこでpushStateメソッドを利用することで、Javascriptから任意のタイミングでブラウザの履歴を追加することができる。

<imput id="btn" type="button" value="カウントアップ" />
<span id="result"> - </span>回クリックされました。
var count = 0;
va result = document.getElementById('result');
// [カウントアップ]ボタンをクリックしたときに履歴を追加
document.getelementById('btn').addEventListener('click', function(){
  result.textContent = ++count;
  history.pushState(count, null, '/js/chap07/count/' + count);
});

// もどるボタンでページの状態を前に戻す
window.addEventListener('popstate', function(e){
  count = e.state;  // pushstateメソッドで追加したデータには、イベントオブジェクトeのstateプロパティでアクセスできうr。stateプロパティから得たカウント値を変数countに書き戻したうえでその値をページにも反映させている。
  result.textContent = count;
});