k4h4shi
7/20/2017 - 2:07 PM

JavaプログラマのJS忘備録[ES5] ref: http://qiita.com/k4h4shi/items/68dd0ceff2e504ce0fae

JavaプログラマのJS忘備録[ES5] ref: http://qiita.com/k4h4shi/items/68dd0ceff2e504ce0fae

var x = 1
{ var x = 2; console.log('x = ' + x); } // x = 2と出力する
console.log('x = ' + x) // ブロックスコープがないため、x = 1と出力する

var i = 1
for (var i = 0; i < 10; i++) {
  // ループの処理
}
console.log(i) // 10と出力される
let x = 1
{ let x = 2; console.log('x = ' + x); } // x = 2と出力する
console.log('x = ' + x) // x = 1と出力する

let i = 1
for (let i = 0; i < 10; i++) {
  // ループの処理
}
console.log(i) // 1と出力される
var s = "string"
var n = 10
var b = true

// ,で区切ることで一つの文で複数の変数を宣言することもできる
var obj = {}, func = function() {};

s // => "string"
n // => 10
b // => true
obj // => {}
func // => function() {}
// オブジェクトリテラルを変数に代入
var person = {name: 'k4h4shi', age: 23}

// 関数の返り値でオブジェクトリテラルを返す
function createPerson() {
  return {
    name: 'k4h4shi',
    age: 23
  }
}

// 引数にオブジェクトリテラルを渡し、名前付きオプションを渡す
function operation({
  name: 'k4h4shi',
  age: 23,
  married: false
})

// 関数リテラルを変数に代入
var func = function() {
  console.log('hello')
}

// 関数の返り値で関数を返す
function returnFunction() {
  return function() {
    console.log('it will be returned.')
  }
}

// 定義済みの関数の引数に関数を渡し、処理を行う
function executeFunction(function() {
  console.log('it will be executed')
})
var s = 'str'
var n = 100
var b = true
var o = {}
var f = function() {}
var undef = undefined
var nul = null

typeof s // => 'string'
typeof n // => 'number'
typeof b // => 'boolean'
typeof o // => 'object'
// 関数はobject型だが'function'と判定される
typeof f // => 'function'
typeof undef // => 'undefined'
// nullはnull型だが'object'と判定される
typeof nul // => 'object'
try {
  console.log("1行目実行中");
  throw new Error("エラー");
  console.log("例外がthrowされると、この行は実行されない");
} catch(err) {
  console.log("エラーが起こった");
  console.log(err.stack);
} finally {
  console.log("finally中のこの文はいつも実行される");
  console.log("リソースの解放をここで行う");
}

/** 実行結果
1行目実行中
エラーが起こった
Error: エラー
  ... 
finally中のこの文はいつも実行される
リソースの解放をここで行う
*/
function validateEmail(email) {
  return email.match(/@/);
}

try {
  const email = 'これはメールアドレスです';
  if (!validateEmail(email)) {
    throw new Error(`メールアドレスが不正です: ${email}`);
    // 例外がthrowされた場合、以降の文は実行されない
  }
  console.log(`メールアドレスは正常です: ${email}`);
} catch(err) {
  console.error(`エラー: ${err.message}`);
}

// 実行結果 => エラー: メールアドレスが不正です: これはメールアドレスです
Boolean('') // => false
Boolean('true') // => true
Boolean('false') // => true
Boolean(true)  // => true
Boolean(false) // => false

!!0 // => false
!!NaN // => false
!!null // => false
!!undefined // => false
!!'' // => false

!!{} // => true

Boolean({}) // => true
Boolean(0) // => false

// オブジェクトは全てtrueになるので注意
var b = new Boolean(false)
!!b // => true

// 論理演算による型変換
b || false // => true
b && false // => false
function a() {
  console.log('a: bを呼び出す前');
  b();
  console.log('a: 終了');
}

function b() {
  console.log('b: cを呼び出す前');
  c();
  console.log('b: 終了');
}

function c() {
  console.log('c: エラーをスローする');
  throw new Error('c error');
  console.log('c: 終了');
}

function d() {
  console.log('d: cを呼び出す前');
  c();
  console.log('d: 終了');
}

try {
  a();
} catch(err) {
  console.log('--- a呼び出し後のerr.stack ---')
  console.log(err.stack);
  console.log('--- 終わり ---');
}

try {
  d();
} catch(err) {
  console.log('--- d呼び出し後のerr.stack');
  console.log(err.stack);
  console.log('--- 終わり ---');
}

/** 処理結果(一部省略) =>

a: bを呼び出す前
b: cを呼び出す前
c: エラーをスローする
--- a呼び出し後のerr.stack ---
Error: c error
    at c (stackTrace.js:15:9)
    at b (stackTrace.js:9:3)
    at a (stackTrace.js:3:3)
--- 終わり ---
d: cを呼び出す前
c: エラーをスローする
--- d呼び出し後のerr.stack
Error: c error
    at c (stackTrace.js:15:9)
    at d (stackTrace.js:21:3)
--- 終わり ---

*/
var obj = { id: 0, name: "unknown" }

for (var prop in obj) {
  console.log(prop) // id, nameが出力される。
  console.log(obj[prop]) // 0, "unknown"が出力される
}
function f() {
  var s = 'hello' 
  function g() {
    console.log(s);
  }
  return g
}

f() // => [Function: g]
// コンストラクタによる生成
var regExp1 = new RegExp('^[0-9]')
regExp.test('foo') // => false
regExp.test('123Bar') // => true

// リテラルによる生成
var regExp2 = /^[0-9]/
regExp2.constructor === RegExp // => true
regExp2.test('123Foo') // => true

regExp2.exec('123') // => [ '1', index: 0, input: '123' ]
// フラグありの正規表現
var regExp1 = new RegExp('^\\s+', 'g')
regExp1.test(' 123 asdf') // => true

var regExp2 = /^\s[abc]/gi
regExp2.test(' A') // => true
(function(n) {if (n <= 1) return 1; else return n * arguments.callee(n - 1); })(5);
function factorial(n) {
  if (n <= 1) {
    return 1;
  } else {
    return n * factorial(n - 1);
  }
}
function MyObject(x, y) {
  this.x = x
  this.y = y
}

MyObject.prototype.show = function() {
  console.log(this.x, this.y)
}

var myInstance = new MyObject(0, 1)
// プロトタイプから振る舞いを引き継いでいるため、0 1 と出力することができる
myInstance.show()

var small = Number.EPSILON // 1と1より大きい最小の値の差
var maxInt = Number.MAX_SAFE_INTEGER; // 表現できる最大の整数
var max = Number.MAX_VALUE; // 表現できる最大の数値
var minInt = Number.MIN_SAFE_INTEGER; // 表現できる最小の整数
var min = Number.MIN_VALUE; // 表現できる最小の数値
var inf = Number.POSITIVE_INFINITY; // 無限
var ninf = Number.NEGATIVE_INFINITY; // マイナスの無限
var nan = Number.NaN; // Not a Number (数値ではない)
var obj = { a:1, b:2, c:3 };
obj.a // => 1
obj['b'] // => 2
// JSON文字列からJavaScriptオブジェクト
var jsonStr = '{"x": 1, "y": 2, "val": "foobar"}';
var obj = JSON.parse(jsonStr);
obj // => { x: 1, y: 2, val: 'foobar' }

// JavaScriptオブジェクトからJSON文字列
var s = JSON.stringify(obj)
s // => '{"x":1,"y":2,"val":"foobar"}'
// 親となるオブジェクト
function Parent() { 
  this.type = 'parent'
  this.isParent = function() {
    return this.type === 'parent'
  }
}
// 子となるオブジェクト
function Child() { 
  this.type = 'child'
}
// 子のプロトタイプに親を設定し引き継ぐ
Child.prototype = new Parent()

// 親子関係にあるインスタンスを生成
var parent = new Parent();
var child = new Child();

parent.isParent() // => true
// プロトタイプから振る舞いを引き継いでいるため呼び出せる
child.isParent() // => false

// インスタンスのconstructorプロパティが適切になるよう設定する
child.constructor // => [Function: Parent]
Child.prototype.constructor = Child
child.constructor // => [Function: Child]
var array = ['zero', 'one', 'two']
array.forEach(function(e, i, a) {
  console.log(e, i, a)
})

// 以下のように出力される
// zero 0 [ 'zero', 'one', 'two' ]
// one 1 [ 'zero', 'one', 'two' ]
// two 2 [ 'zero', 'one', 'two' ]

// その他の値の数値への変換
+true // => 1
+false // => 0
+null // => 0
+undefined // => NaN

// オブジェクトが適切な数値へ変換できない場合はNaNとなる
var obj = {}
obj++ // => NaN

{
  name: 'k4h4shi',
  age: 23
}
String(100) // => '100'
(100).toString() // => '100'

// 暗黙の型変換を利用した文字列への変換のイディオム
var n = 100
n+'' // => 100
// 数値リテラル
var count = 10; // 10進数
var blue = 0x0000ff; // 16進数
var umask = 0o0022; // 8進数
var roomTemp = 22.5; // 少数
var c = 3.0e6; // 指数表記
var e = -1.6e-19; // -の指数表記

// 無効な値
var inf = Infinity; // 無限
var ninf = -Infinity; // マイナスの無限
var nan = NaN; // Not a Number (数値ではない)

// NaNかどうかを判定する関数
isNaN(count) // => false
isNaN(nan) // => true
isNaN(inf) // => false

// 無効な値でないことを判定する関数
isFinite(count) // => true
isFinite(nam) // => false
isFinite(inf) // => false
var x = 0;
while(true) {
  x += 0.1;
  console.log(x);
  // xと0.3の差をとって、その絶対値がNumber.EPSILONより小さい場合、等しいとみなします。
  if (Math.abs(x - 0.3) < Number.EPSILON) break; 
}
var x = 0;
while(true) {
  x += 0.1;
  console.log(x);
  // 3回目のループではxが0.3となることを期待しているが、そうならない。
  // そのためにこのループは無限ループとなる
  if (x === 0.3) break; 
}
function f() {
  var s = 'hello' 
  function g() {
    console.log(s);
  }
  g()
}

f() // 'hello'と出力する
function f() {
  function g() {
    console.log('hello');
  }
  g()
}

f() // 'hello'と出力する
var x = 1
function func() {
  console.log('x = ' + x);
  var x = 2
  console.log('x = ' + x)
}

func()
// 上記のfuncの呼び出しは、以下のように出力する
// x = undefined
// x = 2
// 外側へ向けた名前の探索
function func1() {
  let x = 1
  { console.log(x) } // 1を出力する
}

// let宣言より前でも、名前は有効
function func2() {
  let x = 1
  { 
    console.log(x) // let x = 2のスコープだが、代入前のためにundefinedを出力する
    let x = 2
    console.log(x) // let x = 2によって代入が行われたため、2を出力する
  }
}
var array = [0, 1, 2]
for (var i = 0, len = array.length; i < len; i++) {
  console.log(array[i])
}
// 以下のように出力される
// 0
// 1
// 2
function Parent() {}
function Child() {}
Child.prototype = new Parent()

var child = new Child()
Child.prototype.isPrototypeOf(child) // => true
Parent.prototype.isPrototypeOf(child) // => true
Object.prototype.isPrototypeOf(child) // => true
// シングルクォートで囲った文字列
var s = JSON.parse("'foo'"); // SyntaxError: JSON.parse

// 文字列でないプロパティ名
var s2 = JSON.parse("{x: 1}") // SyntaxError: JSON.parse
var date = new Date()
date instanceof Date // => true
date instanceof Object // => true

function Parent() {}
function Child() {}
Child.prototype = new Parent()

var child = new Child()
child instanceof Child // => true
child instanceof Parent // => true
child instanceof Object // => true

var array = ['x', 'y', 'z']
array.forEach(function(e) { console.log(e) })
x = x || 0 // => xがundefinedの場合0を、そうでなければxをxに代入。
var obj = { prop: 'ownProperty' }

// in演算子
'prop' in obj // => true
'toString' in obj // => true

// hasOwnProperty関数
obj.hasOwnProperty('toString') // => false
obj.hasOwnProperty('prop') // => true
function Person(name, age) {
  this.name = name
  this.age = age
  this.greeting = function() {
    console.log('hello world.')
  }
}

var person = new Person('john', 23);

person.name // => 'k4h4shi'
person.age // => 23
person.greeting // => function() { console.log('Hello!') }
person.greeting() // コンソールにHello!と出力する
function func() {}
func.constructor // => [Function: Function]
func.constructor === Function // => true
func.__proto__ === Function.prototype // => true

function() {
  console.log('hello world');
}
function Parent() {}
function Child() {}
Child.prototype = new Parent()

var child = new Child()
Child.prototype.isPrototypeOf(child) // => true
Parent.prototype.isPrototypeOf(child) // => true
Object.prototype.isPrototypeOf(child) // => true
var date = new Date()
date instanceof Date // => true
date instanceof Object // => true

function Parent() {}
function Child() {}
Child.prototype = new Parent()

var child = new Child()
child instanceof Child // => true
child instanceof Parent // => true
child instanceof Object // => true

1 == '1' // => true
1 === '1' // => false
1 != '1' // => false
1 !== '1' // => true

// 宣言のみの変数の判定
var x;
x === undefined // => true

// 値がnullかの判定
var y = null;
y === null // => true

var obj = {}
obj.operate = function() { console.log('operate!') }

if ('operate' in obj && typeof obj.operate === 'function') {
  // 'operate!'と出力する
  obj.operate()
}
var date = new Date()  // 引数なしのコンストラクタで現在時刻のインスタンス生成
date // => 2017-07-24T14:12:14.415Z

// 日の数値を返す
date.getDate() // => 24
// 0を日曜とする曜日を返す
date.getDay() // => 1

// 年を設定する
date.setFullYear(2018) // => 1532441534415

// 文字列へ変換する
date.toDateString() => 'Tue Jul 24 2018'
date.toString() // => 'Tue Jul 24 2018 23:12:14 GMT+0900 (JST)'
var sum = Function('a', 'b', 'return a + b')
var div = new Function('a', 'b', 'return a - b')

sum(3, 5) // => 8
div(3, 5) // => -2
var date = new Date()
date.constructor // => [Function: Date]
var obj = {}
obj.constructor // => [Function: Object]
var obj = {}
typeof obj.constructor // => 'function'

typeof Object // => 'function'
typeof Object() // => 'object'

obj.constructor === Object // => true
function MyObject() {}
typeof MyObject // => 'function'
var obj = new MyObject()
obj.constructor // => [Function: MyObject]
typeof obj.constructor // => 'function'
var x = 1, y = 2, z;
z = ++x, y++;
z // => 2
var rspModule = (function(x, y) {
  var choise = {r: 'グー', s: 'チョキ', p: 'パー'}
  var errorMsg = 'そうかそうか君はそんなやつだったんだな'

  return {
    win: function(input) {
      switch(input) {
        case choise.r: return choise.p
        case choise.s: return choise.r
        case choise.p: return choise.s
        default: return errorMsg
      }
    }
  }
})()

m.win('グー') // => 'パー'
m.win('チョキ') // => 'グー'
m.win('パー') // => 'チョキ'
m.win('ピストル') // => 'そうかそうか君はそんなやつだったんだな'

// モジュール自体にはプロパティが存在しないためアクセスできない
m.choise // => undefined
function greeting(name) {
  var msg = 'hello ' +  name + '.'
  return function() {
    console.log(msg);
  }
}
function greeting(name) {
  var msg = 'hello ' +  name + '.'
  function g() {
    console.log(msg);
  }
  return g
}

var greeting1 = greeting('anthony')
var greeting2 = greeting('john')
greeting1() // => 'hello anthony'と出力する
greeting2() // => 'hello john'と出力する
function f() {
  var s = 'hello' 
  function g() {
    console.log(s);
  }
  return g
}

var rg = f()
rg() // => 'hello'と出力する
function closure() {
  var cnt = 0;
  return function() { return cnt++ }
}

var fn = closure()
fn() // => 0
fn() // => 1
fn() // => 2
var b = true;
var c = false;

var n = b ? 1 : 0;
n // => 1
var m = c ? 1 : 0;
m // => 0

function boolToNum(b) {
  return b ? 1 : 0;
}

boolToNum(b) // => 1
boolToNum(m) // => 0
// 識別子に使えないプロパティ名を使う場合
var obj = { 'foo-bar': 5}
obj['foo-bar'] // => 5
// obj.foo-bar // obj.fooとbarの減算と解釈されるためにエラー

// 変数の値をプロパティ名に使う場合
var obj = { x: 10 }
var key = 'x';
obj[key] // => 10

// 式の評価結果をプロパティ名に使う場合
// TBD
function func() {
  var x
  console.log('x = ' + x);
  x = 2
  console.log('x = ' + x)
}
var array = [0, 1, 2, 3]
typeof array // => 'object'
array.length // => 4

var array2 = [0, 'str', true, function() {}, {}]
array2.length // => 5

// コンストラクタの生成の際は、1つの数値を指定するとその要素数の配列となる
var array3 = new Array(5)
array3 // => [5 empty items]

// 2つ以上の引数を渡すと、それらを要素とした配列となる
var array4 = new Array(0, 3, 5)
array4 // => [0, 3, 5]

var array = ['1', '2', '0']
// 最後尾に要素を追加
array[array.length] = '3'
array // => ['1', '2', '0', '3']

// 数値配列に変換(要素が数値変換可能な場合)
array.map(function(e, i, a) {
  a[i] = +e
})
array // => [1, 2, 0, 3]

// 数値配列のソート
array.sort(function(a, b) { return a - b; })
array // => [0, 1, 2, 3]

// 配列を使った文字列生成
var arr = []
arr.push('<div>')
arr.push(Date())
arr.push('</div>')
var s = arr.join('') 
s // => '<div>Mon Jul 24 2017 22:41:00 GMT+0900 (JST)</div>'

// 文字列から配列生成
var s = 'Mon Jul 24 2017 22:41:00 GMT+0900 (JST)'
var a = s.split(/\s/)
a // => [ 'Mon', 'Jul', '24', '2017', '22:41:00', 'GMT+0900', '(JST)' ]

// 配列のコピー(shallowコピー)

// concatを用いた場合
var arr = [3, 5, 4]
var arrCp = [].concat(arr)
arrCp // => [3, 5, 4]

// sliceを用いた場合
var arr = [3, 5, 4]
var arrCp = arr.slice(0, arr.length)
arrCp // => [3, 5, 4]

function printArgs() {
  console.log(arguments.length, arugments[0], arugments[1], arugments[2])
}

printArgs(0) // 1 0 undefined undefined
printArgs(0, 1) // 2 0 1 undefined
printArgs(0, 1, 2) // 3 0 1 2
var person = {
  name: 'k4h4shi',
  age: 23,
  greeting: function() {
    console.log('Hello!')
  }
}


person.married = false
person.married // => false
'married' in person // => true
delete person.married // => true
'married' in person // => false


function counter(init) {
  // 変数cntは、Javaにおけるprivateフィールド相当
  // initがundefined、つまり引数が渡されなかった場合に0で初期化するidiom
  var cnt = init ||  0

  return {
    // 以下のプロパティはpublicメソッド相当
    show: function() { console.log(cnt) },
    up: function() { cnt++; return this },
    down: function() {cnt--; return this }
  }
} 

var c = counter();

c.show() // => 0
c.up().show() // => 1
c.down().show() // => 0
var person = {
  name: 'k4h4shi',
  age: 23,
  greeting: function() {
    console.log('Hello!')
  }
}

person.name // => 'k4h4shi'
person.age // => 23
person.greeting // => function() { console.log('Hello!') }