白猫のメモ帳

C#とかJavaとかJavaScriptとかHTMLとか機械学習とか。

JavaScript小ネタ3選

小ネタです。

ブックマークレットはURLエンコードしよう

ブックマークレットは、ブラウザのブックマークから起動する簡易的なプログラムです。
例えば以下のようなブックマークレットを登録して、範囲選択をした状態でブックマークレットをクリックすればGoogleで検索ができます。

javascript:(() => { window.open("https://www.google.com/search?q=" + encodeURIComponent(window.getSelection())); })();

さて、ここで完全一致検索をするためにダブルクォートでくくることにします。

javascript:(() => { window.open("https://www.google.com/search?q=" + "%22" + encodeURIComponent(window.getSelection()) + "%22"); })();

これをクリックすると構文エラーだと怒られてしまいます。
ブックマークレットはあくまでURLなので、URLデコードを試みてこういう扱いになります。

javascript:(() => { window.open("https://www.google.com/search?q=" + """ + encodeURIComponent(window.getSelection()) + """); })();

正しくはこうです。
くっつけてからエンコードしなさいと言われたらその通りですが、意外と引っ掛かりがちな罠です。

javascript:(() => { window.open("https://www.google.com/search?q=" + "%2522" + encodeURIComponent(window.getSelection()) + "%2522"); })();

consoleにはlog以外もいろいろある

JSでデバッグ時にはconsole.logをよく使うと思いますが、実はlog以外にもいろいろとメソッドがあります。
たとえば、debug、info、warn、errorなどがあってログレベルの調整ができたりします。ちなみにlogのレベルはInfoです。

const obj = { hoge: "hoge", fuga: 1, piyo: true};
console.error(console);
console.warn(console);
console.info(console);
console.debug(console);  // デフォルトのログレベルはInfoなのでこれは出ない

DevToolsのこの辺りから変更できます。

dirはプロパティの対話的なリストを表示します。
DevToolsではlogでも結局は対話的に展開できてしまうのであまりメリットを感じませんが、node.jsの時にはよく使います。
第二引数に「{depth: null}」を渡すと一番深いところまで展開された状態で表示されるので、複雑な構造を表示したいときにはより便利です。

const obj = { hoge: "hoge", fuga: [{ piyo: [ 1, 2, 3] }, { piyo: [ 4, 5, 6] }] };

console.log(obj);
// { hoge: 'hoge', fuga: [ { piyo: [Array] }, { piyo: [Array] } ] }

console.dir(obj, {depth: null});
// {
//   hoge: 'hoge',
//   fuga: [ { piyo: [ 1, 2, 3 ] }, { piyo: [ 4, 5, 6 ] } ]
// }

tableはオブジェクトをテーブル形式で表示します。
複雑な構造だとかえって見づらいこともありますが、単純なオブジェクトや配列などを表示する場合には結構便利です。

const obj = { hoge: "hoge", fuga: 1, piyo: true};
console.table(obj);

他にもいろいろあるので見てみるといいかも。
developer.mozilla.org

mixinができる

ES6からJavaScriptではclass構文が使えるようになりました。
これは糖衣構文なので他の言語からするとなんだか違和感のある使い方ができてしまうのですが、これによってmixinを実現することができます。
例えばこんなクラス定義をしたとします。

class Hoge {
    name = "hoge";
}

const hoge = new Hoge();
console.log(hoge.name);  // hoge

ここで型を引数で受けて継承したclassを返す関数を作るとmixinができます。return classの気持ち悪さよ…。

const mixin = (Base) => {
    return class Fuga extends Base {
        getName() {
            return this.name + this.name;
        }
    };
};

const Fuga = mixin(Hoge);
const fuga = new Fuga();
console.log(fuga.getName());  // hogehoge

ちなみにどうでもいいんですが個人的に気持ち悪いなと思っている文法はいくつかあって、例えばJavaのネストクラスのインスタンス生成あたりもちょっとキモいなと思っています。
なんというかスペースとドットの使われ方の問題でしょうか。

class Hoge {
    class Fuga {
    }
}

var fuga = new Hoge().new Fuga();

似たようなもので、これは割とどの言語もだと思いますが、awaitの結果をメソッドチェーンにする場合には先に評価するためにカッコを求められるのに、

async function hoge() {
    return {name: "hoge"};
}

const hogeResult = (await hoge()).name;
console.log(hogeResult );

否定の時にはそのままawaitの前に!を置いていい辺りがなんかキモさがあります。いやまぁなくても評価できるので正しいとは思うのですが。

async function fuga() {
    return true;
}
const fugaResult = !await fuga();
console.log(fugaResult);