タグ別アーカイブ: JavaScript

GNOME 3.26 gjs class

おまたせ、gjs の ES6 class でアプリを作る方法がやっと解ったよ。
PyGObject みたく親切に例外を吐くなんてしてくれないので厳しい。

注意点、constructor はマジでコンストラクタです。
Python の __init__ 等と違う、動的言語でまさかこの仕様だとは。
細かい説明はしないけど、つまり super() 以外は何もできない。
継承で色々行う場合は下記のように別関数にする等の必要あり。

/*
const MyWindow = new Lang.Class({
    Name: 'MyWindow',
    Extends: Gtk.ApplicationWindow,

    _init: function(app) {
        this.parent({application: app});
        this.createContents();
        // etc...
*/
var MyWindow = GObject.registerClass({
    GTypeName: "MyWindow",
}, class MyWindow extends Gtk.ApplicationWindow {
    constructor(props={}) {
        super(props);
    }
    create() {
        this.createContents();
        // etc...

更に constructor の引数はベースへの property を JSON でに限定。
他を入れるとエラーになるのでとにかくこう書く以外に手段は無いみたい。

override で継承元の関数を呼ぶには super からドットで呼び出す。
Lang.Class ではないので this.parent() は使えない。

var MyApplication = GObject.registerClass({
    GTypeName: "MyApplication"
}, class MyApplication extends Gtk.Application {
    constructor(props={}) {
        super(props);
    }
    vfunc_startup() {
        //this.parent();
        super.vfunc_startup();

コレはすぐ気が付くか。

それ以外は今までのコードをそのまんま使えるようだ。
var にする必要があるのは外部から使う class だけでいいみたい。

本当は物凄い遠回りをしたんだけど以上であるようだ。

ということで、もう少し実験してから Y901x を更新する。
ぶっちゃけ動画プレイヤーは gnome-mpv でイイんだけど
Y901x は gjs のサンプルコードがメインの仕事だったことを忘れる所だった。

GNOME 3.26 gjs p2

散々探してやっと見つけた。

Inventing GObject ES6 classes | The Mad Scientist Review

なんかイッパイ手段があるみたい。
一番簡単そうな手段で試してみる。

/* btn.js */

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

var Btn = GObject.registerClass({
    GTypeName: "BtnClass"
}, class Btn extends Gtk.Button {
    constructor(props={}) {
        super(props);
    }
    // function
    set_button_label(txt) { this.label = txt; }
    // getter
    get prop() { return this.label }
});

#!/usr/bin/gjs

imports.gi.versions.Gtk = "3.0";
imports.searchPath.unshift('.');

const Gtk = imports.gi.Gtk;
const Btn = imports.btn;

class Test extends Gtk.Window {
    constructor() {
        super();
        this.connect("hide", ()=> {
            Gtk.main_quit();
        });
        this.ll = "カワイイ";
        var btn = new Btn.Btn({label: "睦ちゃん"});
        btn.connect("clicked", (widget)=> {
            // getter
            var s = widget.prop;
            // function
            widget.set_button_label(`${s} ${this.ll}`);
        });
        this.add(btn);
        this.show_all();
    }
}

Gtk.init(null);
let test = new Test();
Gtk.main();

で動かしてみる。

何も警告は出なくなった、思いっきり const を使っているのに。
これで安心してコード分割ができるぞい。
ただ、ちょっぴり面倒臭い。

関数定義や getter/setter は検索して一番解りやすかったページが以下。

JavaScriptにもクラスがやってきた!JavaScriptの新しいclass構文をマスターしよう | HTML5Experts.jp

コピペして console.log を print に書き換えてと。
うん gjs 1.50.2 で問題なく動くんだね。
だけど gir で継承すると…

#!/usr/bin/gjs

imports.gi.versions.Gtk = "3.0";

const Gtk = imports.gi.Gtk;
Gtk.init(null);

//* gir @ Error
class Btn extends Gtk.Button {
    constructor() { super(); }
    put() { print("func test"); }
}
//*/

/* no gir @ OK!
class Btn {
    constructor() {}
    put() { print("func test"); }
}
*/
var btn = new Btn();
btn.put();

何でや!

getter/setter も同様だった、理由が解らない。
上記のように GObject.registerClass をするしかないっぽい。
class が使えるようになって面倒になるとは思わなかったよ。

GNOME 3.26 gjs

GNOME 3.26 の目玉、gjs が ES6 フル対応になった。
これでで class が使えるぞ、Lang.Class の奇妙なコードとはおさらばじゃ。
んと、その前に。

#!/usr/bin/gjs

// 'gjs a.js 苗ちゃん'

const GLib = imports.gi.GLib;

for (let val of ARGV) {
    print(val);
    //let s = decodeURIComponent(escape(val));
    //print(s);
}

変わっていないや、まあいいか。
ClutterImage のセットが激遅なのもそのまんまだね。
ClutterImage PyGObject/Gjs | PaePoi

それはそれとして新機能だ。
GtkWindow を作ってみよう、やっぱり GUI だよね。

#!/usr/bin/gjs

imports.gi.versions.Gtk = "3.0";

const Gtk = imports.gi.Gtk;

class Test extends Gtk.Window {
    constructor() {
        super();
        this.connect("hide", ()=> {
            Gtk.main_quit();
        });
        this.show_all();
    }
}

Gtk.init(null);
let test = new Test();
Gtk.main();

これでウインドウを作るだけの最小限コードのようだ。

imports は PyGObject と同様にバージョン指定が無いと警告が出るようになった。
アロー関数を使えば Lang.bind を使わずにあの this の糞仕様を回避できる。
他の説明はいらないよね。

次はコード分割してみよう。

#!/usr/bin/gjs

imports.gi.versions.Gtk = "3.0";
imports.searchPath.unshift('.');

const Gtk = imports.gi.Gtk;
const Btn = imports.btn;

class Test extends Gtk.Window {
    constructor() {
        super();
        this.connect("hide", ()=> {
            Gtk.main_quit();
        });
        this.btn = new Btn.Btn("睦ちゃん");
        this.add(this.btn);
        this.show_all();
    }
}

Gtk.init(null);
let test = new Test();
Gtk.main();

var Gtk = imports.gi.Gtk;

class Btn extends Gtk.Button {
    constructor(lb) {
        super({
            label: lb
        });
    }
}

えーーーーー
let も const も定義していないお!
Java と違って同一ソースに複数の class が書けるのでこうすればいいけど。

#!/usr/bin/gjs

imports.gi.versions.Gtk = "3.0";

const Gtk = imports.gi.Gtk;

class Test extends Gtk.Window {
    constructor() {
        super();
        this.connect("hide", ()=> {
            Gtk.main_quit();
        });
        this.btn = new Btn("睦ちゃん");
        this.add(this.btn);
        this.show_all();
    }
}

class Btn extends Gtk.Button {
    constructor(lb) {
        super({
            label: lb
        });
    }
}

Gtk.init(null);
let test = new Test();
Gtk.main();

コードが長くなると…

モジュールとして継承 class は作ってはいけないってことかな?
まだ試したばかりだし他の方法はあるかもしれないけど。
なんか一気にテンションが下がった、PyGObject に戻るかなぁ。。。

surrogate-pair

JavaScript における文字コードと「文字数」の数え方 | blog.jxck.io

そうだった、Python3 ばかり使っていたのでサロゲートペアのことを忘れていた。
GLib が扱う Unicode も Linux,macOS 版 Python3 の文字列も UCS-4 なんだよね。
Windows は捨てたので Windows 版 Python3 は知らん、ってどうでもいいか。

ES6 では for of を使って Python3 と同様な処理ができるようだ。
もちろん Node.js, JavaScriptCore も同様の結果でした。

UTF-16 はこの件があるし UTF-8 との変換も面倒だしetc…
何故いまだに Unicode の主流なんだろうね。
メモリ効率うんぬんならスクリプト言語や仮想マシンの時点で、って話だし。

おっと、一番下を見逃す所だった。

Family: Man, Woman, Girl, Boy Emoji

Emoji にはこんな文字をくっつけた一文字があったのか!
コピペしたら WordPress で投稿できないぞ、つかイッパイあるなぁ。

Emoji Version 2.0 List

Python3 でも駄目だ、バイナリを見れば当然だけど。
こんな文字まで考慮しなきゃいけない時代になってしまったのか。

JavaScript Arrow Function

前回 Gjs の ES6 がって書いたけど。
よく考えたら現在 JavaScriptCore や V8 も試せる環境じゃないか。
現状 (2017.10.10) ではどうなのか実験。

Gjs(SpiderMonkey) は 1.48.7
Node.js(V8) は dnf で入る v6.11.3
JavaScriptCore はワカラン、Fedora 26 の /usr/libexec/webkit2gtk-4.0/jsc
jjs(nashorn) は1.8.0_144、–language=es6 オプションで。

jsc は .bashrc にエイリアスを作って準備してと。
Node.js だけ console.log なのを無理矢理 print となるようにしてと。

とりあえず無名関数とアロー関数での this スコープの違い。

// @ Node.js
if (typeof print === "undefined")
    print = console.log; 

let obj = {
    func: function () {
        this.str = "優木苗";
 
        let funcA = function () {
            print(this.str);
        };
        let funcB = () => {
            print(this.str);
        };
        funcA();
        funcB();
    }
};
obj.func();

jjs はアロー関数に対応していなかった。
他は全部対応済なのね、ふむふむ。
Gjs はワーニングを出してくれる親切仕様、イラネーけど。

次は同一ブロックでの let 変数名の多重定義。

// @ Node.js
if (typeof print === "undefined")
    print = console.log; 

let n = 13;
let n = 99;
//n = 66;
print(n);

って、おい SpiderMonkey!
jjs ですらエラー判定するのに、まあ次は対応済と解っているけど。
それにしても Node.js のエラー表示はウゼェ。

次に class を作ってみよう、Gjs はまだ対応していないと解っているけど。

// @ Node.js
if (typeof print === "undefined")
    print = console.log; 

class Test {
    constructor(str) {
        print(str);
    }
}
let test = new Test("むったん");

だよね。
JavaScript の仕様策定は Mozilla がやっているはずなのにな。