JavaScript」タグアーカイブ

Fedora 32 JavaScript

Fedora 32 は Gjs が ES2019 にフル対応した。
いや、フル対応した SpiderMonkey にアップデートというべきか。
JavaScriptの ES2019で追加された新機能まとめ – Qiita

更に BigInt にも対応、素晴らしい。
Python 屋としては Number の拡張はできなかったのかと言いたい所だけど。

bigint

プライベートフィールド等は駄目でした。
そんなことより Gjs の開発者はかなりがんばったようだ。

ClutterImage PyGObject/Gjs | Paepoi Blog

gjs_speedup

まさかの PyGObject より速くなるとは、誤差の範囲とはいえ。
何をやったか解らないけどコレで Gjs を諦める理由が減った。

Gjs: GdkPixbuf Memory leak | Paepoi Blog

この意味不明メモリリークもやっと起こらなくなった。
やはりメンテを続けていると良くなっていくんだよね。
ただこの実験は Python のガベージコレクションの凄さを思い知るだけだが。
メンテを続けた年期の差ってことで。

ところで JavaScript といえば。
/usr/libexec/webkit2gtk-4.0/jsc
が無くなった、Nautilus の検索機能でも見つからない。
けれど gir に JavaScriptCore-4.0.typelib は残っている。

#!/usr/bin/python

import gi
gi.require_version('JavaScriptCore', '4.0')
from gi.repository import JavaScriptCore

context = JavaScriptCore.Context()
out = context.evaluate('3 + "あ" + 4', -1)
print(out.to_string())

//=> '3あ4'

これは動く。

SpyderMonkey, V8 同様に実体が無くライブラリだけになったみたい。
実験にしか使っていなかったし mac も持っているから別にイイか。

CRLF

何を今頃だけど JavaScript の replace について。

String.prototype.replace() – JavaScript | MDN

第一引数を正規表現にすればすべてのマッチした箇所を置換できるのか。
最初に一致した箇所だけだとずっと勘違いしていた筆者であった。

JXA: doShellScript Line feed code | Paepoi Blog

これを試しに書き換えしてみよう。

#!/usr/bin/osascript

let app = Application.currentApplication();
app.includeStandardAdditions = true;

res = app.doShellScript('ls -l');
console.log(res.replace(/\r/g, '\n'));

いけた。

ついでに。
よく考えたらコマンドの中で tr を使って変換すりゃいいじゃん。
と思ってやってみたら上手くいかなかった。

#!/usr/bin/osascript

let app = Application.currentApplication();
app.includeStandardAdditions = true;

// no...
//res = app.doShellScript('ls -l | tr "\r" "\n"');

// test
res = app.doShellScript('ls -l | tr "\n" "|"');
console.log(res);

となる。

つまりコマンド実行の時点では改行コードは LF のまま。
doShellScript が値を戻す時に CR へ変換しているようです。
LF のまま戻すオプションって無いのかな?

lf

#!/usr/bin/osascript

let app = Application.currentApplication();
app.includeStandardAdditions = true;

res = app.doShellScript('ls -l', {alteringLineEndings:false});
console.log(res);

あった、今後はコレで。

ついでに、doShellScript は bash の POSIX 互換モードです。
zsh やフル状態の bash ではないので注意、macOS って本当に色々面倒臭い。
プログラミングするならやっぱり Linux だよ、某サル専用を除く。

関係ないけど Macbook Air 2020 が出たね、かなり良さげ。
でも筆者はこんな使い方ばかりだから 2018 モデルで何の不満も無いのよね。
ペチペチキーボードにもすっかり慣れてしまったし、うるさいけど。
さて 10.15.4 にアップデートするか。

JavaScript: padStart

String.prototype.padStart() – JavaScript | MDN

あれ?いつのまにこんなメソッドが追加されたんだろう。
これを使えば JavaScript でもゼロ詰めするだけの処理が不要になるぞと。

'7'.padStart(4, '0');

Fedora 30 で試して SpiderMonkey, JavascriptCore, V8 全部使えると確認。
V8 は node.js でとも思うんだがコレも IE, Android 同様バージョン関係がややこしい。
Apple の SandBox は「全部同梱を強要」という実は Unux と真逆の存在だったりするけど、なるほどって思う。
エロゲ専用に落ちぶれた OS はどうでもいい。

筆者が Fedora, macOS に絞ったのはこの二つのユーザーは確実に最新版を使うという理由もある。
LTS がある Ubuntu がサーバー用途で人気なのも当然、Desktop 版は今やサル専用、完全に宗教。
GNOME2 時代はコレし無いって感じだったのに道を間違えたよね、それはここでは関係なくて。

formatting – Pad a number with leading zeros in JavaScript – Stack Overflow

全部無駄になっちゃった。
でもこういうのを考えるのも経験値だとも。
とりあえず覚書ページに追記しとこう。

JavaScript Date

JavaScript 覚書で jjs を削除し他を今風に書き換え。
だけじゃつまらないから何か追記したい。

日付けと時刻の取得はまだ Gjs でしかやっていなかった。
よしこれを JXA, Node.js で行う手段を探し、、、、、いやまて。
よく考えたら JavaScript には Date オブジェクトがあった。

/**
 * Gjs, JXA, Node.js 共通
 */

const WEEKS = ['日','月','火','水','木','金','土'];

let now = new Date();

let year  = now.getYear() + 1900;
let month = now.getMonth() + 1;
let day   = now.getDate();
let week  = WEEKS[now.getDay()];
let hour  = now.getHours();
let minut = now.getMinutes();
let sec   = now.getSeconds();

if (month < 10) month = '0' + month;
if (day   < 10) day = '0' + day;
if (hour  < 10) hour = '0' + hour;
if (minut < 10) minut = '0' + minut;
if (sec   < 10) sec = '0' + sec;

if (typeof print === 'undefined') print = console.log;
print(`${year}年${month}月${day}日(${week}) ${hour}:${minut}:${sec}`);

で。

ウエブブラウザでも使える、JavScriptCore 単体でも動く。
.bashrc にエイリアスを作って試してみよう。

# Fedora alias
alias jsc=/usr/libexec/webkit2gtk-4.0/jsc

# macOS alias
alias jsc=/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc

あ、仕事は遅番出勤ですので。

ところで、以下で検索するとやはりというかなんというか。
‘node.js 日付と時刻’

strftime 形式で日時取得ごときにインストール…
何故いつもいつもインストールばかりやっているのだ?
その程度を自分で作れない輩にいったい何が作れるのだ?

%H,%M,%S だけの実装例を書いてみる。
datetime.now なのはもちろん Python に合わせた。

const datetime = {
    now(fmt) {
        let now = new Date();
        let kwd = false;
        let res = [];
        for (let s of fmt) {
            if (kwd) {
                switch (s) {
                case 'H':
                    s = now.getHours();
                    if (s < 10) s = '0' + s;
                    break;
                case 'M':
                    s = now.getMinutes();
                    if (s < 10) s = '0' + s;
                    break;
                case 'S':
                    s = now.getSeconds();
                    if (s < 10) s = '0' + s;
                    break;
                default:
                    throw 'undefined format';
                }
                kwd = false;
            } else {
                if (s === '%') {
                    kwd = true;
                    continue;
                }
            }
            res.push(s);
        }
        return res.join('');
    }
}
if (typeof print === "undefined") print = console.log;
print(datetime.now('%H:%M:%S'))

15 分で作れた。

Google さん、もっとまともなサイトを上位に表示してよ。

MessageBox.show @ Gjs and PyGObject

JavaScript の static メソッドはインスタンスからは呼び出しできない。

#!/usr/bin/gjs
 
class A {
    constructor(arg) {
        this.num = 'instance';
    }
    static static_method() {
        return 'staticmethod';
    }
}
A.num = 'static';
a = new A();
print(a.num); //=> instance
print(A.num); //=> static

print(A.static_method()); //=> staticmethod
print(a.static_method()); //=> ERROR!

当然である。
JavaScript の class は prototype の別表現でしかないから。

#!/usr/bin/gjs

function A() {}
A.func = function() {
    return 'staticmethod';
}
A.prototype.func = function() {
    return 'instancemethod';
}

print(A.func()); //=> staticmethod
let a = new A();
print(a.func()); //=> instancemethod

Python,C# 等の他言語ではインスタンスからでも呼び出しできる。

#!/usr/bin/env python3
 
class A:
    def __init__(self):
        self.num = 'instance'
    @staticmethod
    def static_method():
        return 'staticmethod'

A.num = 'static'
a = A()
print(a.num) #=> instance
print(A.num) #=> static

print(a.static_method()) #=> staticmethod
print(A.static_method()) #=> staticmethod

特に C# でよく見るけど、わざわざインスタンスを作ってからスタティックメソッドを使っている人の異様な多さを見ると JavaScript みたいなアクセスのほうがいいような。

そんなことより。
スタティックメソッドとインスタンスメソッドで同じ名前を指定してもいいんだ。
あまり自分のコードでスタティックを作らないから知らなかったよ。

ということで。
GtkMessageDialog で MessageBox.show を作ってみよう。
MessageBox.Show ではどちらの言語のコーディングスタイルにも合わないからね。
Gir の Gtk.Widget には show メソッドがあるけど無視できる。

#!/usr/bin/gjs

const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;

var MessageBox = GObject.registerClass({
    GTypeName: "MessageBox"
}, class MessageBox extends Gtk.MessageDialog {
    _init(text) {
        super._init({
            buttons: Gtk.ButtonsType.OK,
            text: text,
            secondary_text: "test"
        });
    }
    static show(text) {
        //let dlg = new MessageBox(text); @ error!
        let dlg = new this(text);
        dlg.run();
        dlg.destroy();
    }
});

Gtk.init(null);
MessageBox.show("Message");

new this(text) って変な感じ。

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class MessageBox (Gtk.MessageDialog):
    def __init__(self, text):
        Gtk.MessageDialog.__init__(
            self,
            buttons=Gtk.ButtonsType.OK,
            text=text,
            secondary_text="test" )
    @staticmethod
    def show(text):
        #dlg = self(text) @ error!
        dlg = MessageBox(text)
        dlg.run()
        dlg.destroy()

#Gtk.init(None) @ no need
MessageBox.show("Message")

PyGObject だとこう。

GUI を作っている時の print 代わりに。