Paepoi

Paepoi » JavaScript Tips » JavaScript 全般の覚書

JavaScript 全般の覚書

# 最終更新日 2019.08.05

ゼロ詰め、typeof、三項演算子の追加、一部加筆修正等を行いました。

通称コマンド名動作環境コア主なブラウザ
GjsgjsGNOMESpiderMonkeyFirefox
JXAosascriptmacOSJavaScriptCoreSafari
Node.jsnodeマルチV8 Google Chrome

文字列操作
// console.log を無理矢理 print にする
if (typeof print === 'undefined') print = console.log;


let STR = '漢字も一文字だもん!';

let a = STR.slice(3, 6);     // (開始位置 ,終了位置)
let c = STR.substring(3, 6); // (開始位置 ,終了位置)
let b = STR.substr(3, 3);    // (開始位置 ,切り出す長さ)
print(a, b, c);
//=> 一文字 一文字 一文字

print(STR.slice(3));     // (開始位置のみ指定)
//=> 一文字だもん!


// ループ(サロゲートペア、emoji に対応)
for (let s of '🎴あ⛔') {
    print(s);
}
/* =>
🎴
あ
⛔
*/


// 検索
STR.startsWith('漢字'); // 最初
//=>true
STR.endsWith('もん!'); // 最後
//=>true
STR.indexOf('も'); // 最初の出現位置、存在しなければ -1 が戻る
//=>2
STR.lastIndexOf('も'); // 最後の出現位置、存在しなければ -1 が戻る
//=>7
STR.includes('もん'); // 含まれている? (es5: STR.indexOf('もん') !== -1;)
//=>true
STR.replace('もん', 'モン'); // 変換
//=>漢字も一文字だモン!

print('ABCdef'.toLowerCase());
//=>abcdef
print('ABCdef'.toUpperCase());
//=>ABCDEF


// 前後の空白や最後の改行を取り除く
// 前方のみなら trimStart、後方のみなら trimEnd を使う
let f = '  aa bb cc   \n';
print(f.trim());
//=> 'aa bb cc'


// 変換
let str = '文字列をUTF-8に';
let utf8str = unescape(encodeURIComponent(str));
let utf16str = decodeURIComponent(escape(utf8str));
print(utf16str); // JavaScript 文字列は UTF-16LE

// 文字列を配列に
let inLF = `スズキの
バイクは
カッコイイ`;
let arr = inLF.split('\n');
print(arr);
//=> [スズキの, バイクは, カッコイイ]

// 配列を文字列に
let st = arr.join('');
print(st);
//=> スズキのバイクはカッコイイ

// コードポイントを UNICODE 文字に変換
// Python では chr(97)
String.fromCharCode(97);
//=> 'a'

// UNICODE 文字をコードポイントに変換
// 引数の数値は先頭から何番目か、一文字ならゼロでいい
// Python では ord('a')
'a'.charCodeAt(0);
//=> 97

// サロゲートペアにも対応が必要な場合は以下を使う
// UTF-16 範囲は上記と同じ結果になる
// ちなみに Python3 は UCS-4 なので気にする必要なし
String.fromCodePoint(9940);
//=> '⛔'
'⛔'.codePointAt(0);
//=> 9940

// ゼロ詰め
'7'.padStart(4, '0');
//=> '0007'

配列と連想配列
if (typeof print === 'undefined') print = console.log; 

// indexOf, lastIndexOf, includes は文字列と同様に使えます

// 配列宣言
let array = ['YAMAHA', 'HONDA', 'SUZUKI', 'KAWASAKI'];
// 追加
array.push('MAZDA');
// 前方に追加
array.unshift('TOYOTA');
// 書き換え
array[1] = 'SUBARU';
// 削除
array.splice(4, 1); // 4 番目から 1 つ分取り除く

// 合体、書き換えではなく戻り値なので注意
array = array.concat(['HINO', 'ISUZU'])

// 要素数
print(array.length);

// 含まれている?
if (array.includes('HONDA')) {
    print('あるよ');
}

// ループ 
for (let s of array) {
    print(s);
}
/* output
7
あるよ
TOYOTA
SUBARU
HONDA
SUZUKI
MAZDA
HINO
ISUZU
*/


// ar = [3, 3, 3, 3, 3] になる
let ar = new Array(5).fill(3);


// 連想配列、Python と同様の以下は Objects で不便。
// let map = {'TOYOTA': 'LEXUS', 'HONDA': 'ACURA'};
// ES6 で Map が追加されたのでそちらを

let map = new Map();

// 追加
map.set('SUZUKI', 'Hayabusa');
map.set('HONDA', 'CBR1000RR');
map.set('YAMAHA', 'XMAX');
map.set('KAWASAKI', 'Z900RS');
// 書き換え
map.set('HONDA', 'Super Cub');
// 削除
map.delete('YAMAHA');

// 値の取り出し
if (map.has('KAWASAKI')) {
    let n = map.size;
    let k = map.get('KAWASAKI');
    print(`${n} 個のエントリー\n${k} が含まれています`)
}

// ループ
for (let [key, val] of map) {
    print(`${key} は ${val} です`);
}
/* output
3 個のエントリー
Z900RS が含まれています
SUZUKI は Hayabusa です
HONDA は Super Cub です
KAWASAKI は Z900RS です
*/

let, const
// let 宣言された変数はブロック内スコープになる
// ブロック外の同一名変数に影響を与えない

if (typeof print === 'undefined') print = console.log; 

let letStr = 1;
var varStr = 1;

// 同一ブロックでの多重定義は Error になる
//let letStr = 4;

// var 宣言はブロック内スコープにならない
if (true) {
    let letStr = 2;
    var varStr = 2;
    let letBlock = 3;
    var varBlock = 3;
}

print(`letStr=${letStr} varStr=${varStr} varBlock=${varBlock}`);
//=> letStr=1 varStr=2 varBlock=3
try {
    print(letBlock);
} catch {
    print('letBlock は参照できません');
}

// const は他の言語と同様に変更できない定数になる
// 関係ないけど Swift では定数が let なのはややこしい

const SUZUKI = 'カッコイイ';
try {
    SUZUKI = 'カッコワルイ';
} catch {
    print('SUZUKI のバイクはカッコイイです');
}

テンプレートリテラル
if (typeof print === 'undefined') print = console.log; 

// 普通の変数を ${} で囲んで使います
let val = 'シングルクォート';

// Python の r'' 同様にエスケープシーケンスを無視するには
let raw = String.raw`この \n は改行されない`;

// ヒアドキュメントとほぼ同様
print(`バッククォートで囲みます
${val}ではありません
改行部は普通に \\n になります
${raw}`);

/* output
バッククォートで囲みます
シングルクォートではありません
改行部は普通に \n になります
この \n は改行されない
*/

メソッド定義の簡略構文
// 一般的な Class と似たような使い方ができます
// プロトタイプと違い new は不要
// 'func1: function() {' と書けば ES5 でも使えます

if (typeof print === 'undefined') print = console.log; 

const App = {
    _num: '666',
    func1() {
        return 'Hello';
    },
    func2() {
        return this._num;
    }
}

print(App.func1());
print(App.func2());

クラス
// クラスはプロトタイプベース継承の糖衣構文です
// なので一般的なクラスとは動作が違う場合があります
// たとえば static メンバはインスタンス化すると無効になります
// gir の継承ではコンストラクタを抜けるまで継承元が作成されない等々

if (typeof print === 'undefined') print = console.log; 

/* 下記と同じものを ES5 以前で書くと
var TestClassBase = function(num) {
    this._num = num;
}
TestClassBase.staticFunc = function() {
    print('staticFunc');
}
TestClassBase.prototype.instanceFunc = function() {
    print('instanceFunc');
}
*/
class TestClassBase {
    constructor(num) {
        // コンストラクタ、メンバ変数の初期化等を行う
        this._num = num;
    }
    static staticFunc() {
        print('staticFunc');
    }
    instanceFunc() {
        print('instanceFunc');
    }
}

// サブクラスを作る時は extends を使う
// constructor の引数は親に合わせる必要は無い
class TestClass extends TestClassBase{
    constructor() {
        // 継承元の初期化
        super(7);
    }
    getNum() {
        return this._num;
    }
}

// static 関数は他言語と同様
TestClass.staticFunc();

// インスタンス化
const tc = new TestClass();
tc.instanceFunc();
//tc.staticFunc(); // インスタンス化すると static 関数は呼び出しできない

print(tc.getNum());  //=> 7

ゲッター、セッター
if (typeof print === 'undefined') print = console.log; 

class TestClass {
    constructor() {
        this._width = 0;
        this._height = 0;
    }
    get width() {
        return this._width;
    }
    set width(num) {
        if (num <= 300) {
            this._width = num;
        } else {
            print('300 以上にはできません');
            this._width = 300;
        }
    }
    get height() {
        return this._height;
    }
}

const tc = new TestClass();
tc.width = 400; //=> 300 以上にはできません
print(`width は ${tc.width} です`); //=> width は 300 です
tc.height = 400; //=> height に setter は定義されていないのでエラー

非同期で実行
// 色々な書き方があるけど非同期にしたいだけならコレが一番簡単

if (typeof print === 'undefined') print = console.log; 

Promise.resolve(null)
    .then((value)=> {
        print('いーち');
    })
    .then((value)=> {
        print('にー');
        return 'さーん';
    })
    .then((value)=> {
        print(value);
        return 'だぁ!!!'
    })
    .then((value)=> {
        print(value);
    })
    .catch(function (error) {
        print(error);
    });

print('いくぞー');

/* output
いくぞー
いーち
にー
さーん
だぁ!!!
*/

8 進数, 2 進数
// 8 進数は 0o*、2 進数は 0b* が ES6 で追加された
// 16 進数は 0x* なのは従来どおり

if (typeof print === 'undefined') print = console.log; 

print(0x0d); //=> 13
print(0o76); //=> 62
print(0b10); //=> 2

typeof
if (typeof print === 'undefined') print = console.log;

let BOOL = true;
let NUM = 3.14
let STR = 'SUZUKI';
function func() {}
class Cls {}

print(typeof MITEIGI);
//=> undefined

print(typeof BOOL);
//=> boolean

print(typeof NUM);
//=> number # float も int も数値なら number

print(typeof STR);
//=> string # char というタイプも無い

print(typeof func);
//=> function

print(typeof Cls);
//=> function # Javascript の class は function の別表記

print(typeof new Cls);
//=> object # new で作られたインスタンスは object

print(typeof [3, 4]);
//=> object # 配列や null も object

三項演算子
if (typeof print === 'undefined') print = console.log;

let s = 'smb://macbook.local/';

/*
let の変数スコープの関係で以下のように書けない、if の前に path を定義する必要あり
こういう場合に三項演算子を使うとスマートかつ読みやすいコードになる

if (s.includes('//')) {
    let path = 'URI';
} else {
    let path = 'Path 名';
}
*/
let path = s.includes('//') ? 'URI' : 'Path 名';
print(`引数は ${path} です`);

/*
# ちなみに Python なら if の始まりインデント位置のスコープ扱いになります

if '//' in s:
    path = 'URI'
else:
    path = 'Path 名'
print(f'引数は {path} です')
*/

Copyright(C) sasakima-nao All rights reserved 2002 --- 2020.