Gobble up pudding

プログラミングの記事がメインのブログです。

MENU

JavaScriptで静的変数

スポンサードリンク

f:id:fa11enprince:20200513231943j:plain 例えば次のような処理を考えてみます。
名前と身長と体重を与えると、その人のBMIがメソッドにより出力されるというものです。
さらに、食料foodNumがあって、食べると1つ減って、
代わりに1kg増えるものとします。食料はあらかじめ、貯蔵量に限界があって、減る一方とします。
一人の人のを都度処理するなら下記のような感じで書くと思います。
Vueとか使ってるとよく使うオブジェクトリテラルっす。

// 小数第N位で四捨五入
function roundFloat(number, n) {
    var _pow = Math.pow(10 , n);
    return Math.round(number * _pow) / _pow;
}
(function() {
    // Object Literal
    var person = {
        name: 'Bob',
        height: 180,
        weight: 65,
        foodNum: 10,  // classにしたときにこれを静的変数にしたい…
        bmi: function() {
            if (!this.height || !this.weight) {
                return 0;
            }
            return roundFloat(this.weight / Math.pow(this.height / 100, 2), 2);
        },
        show: function() {
            console.log('name: ' + this.name + ", bmi: " + this.bmi() + ", foodNum: " + this.foodNum);
        },
        eat: function() {
            if (this.foodNum != 0) {
                this.foodNum--;
                this.weight += 1;
            }
        }
    };
    person.show();
    person.eat();
    person.show();
})();

出力結果はこんな感じです

name: Bob, bmi: 20.06, foodNum: 10
name: Bob, bmi: 20.37, foodNum: 9

ただ、複数人のを一度に処理したいときにclass化してかつ、foodNumは共有資源で誰かが食べると、
みんなの分が減るものとします(なんか怖いですが)。
そうした時に、global変数以外では静的変数にしたくなります。
しかし、JavaScriptには静的変数がありません…。というのでこうやってしまおう!というもの。

ES5版

function roundFloat(number, n) {
    var _pow = Math.pow(10 , n);
    return Math.round(number * _pow) / _pow;
}
(function() {
    // Class
    var Person = function(name, height, weight) {
        if (!(this instanceof Person)) {
            return new Person(name, height, weight);
        }
        this.name = name;
        this.height = height;
        this.weight = weight;
    };
    Person.prototype.bmi = function() {
        if (!this.height || !this.weight) {
            return 0;
        }
        return roundFloat(this.weight / Math.pow(this.height / 100, 2), 2);
    };
    Person.prototype.show = function() {
        console.log('name: ' + this.name + ", bmi: " + this.bmi() + ", foodNum: " + Person.foodNum);
    };
    Person.prototype.eat = function() {
        if (Person.foodNum && Person.foodNum != 0) {
            Person.foodNum--;
            this.weight += 1;
        }
    }
    Person.foodNum = 10;  // static variable

    var person1 = new Person('Bob', 180, 65);
    person1.show();
    person1.eat();
    person1.show();
    var person2 = new Person('Alice', 170, 50);
    person2.show();
    person2.eat();
    person2.show();
})();

出力結果

name: Bob, bmi : 20.06, foodNum: 10
name: Bob, bmi : 20.37, foodNum: 9
name: Alice, bmi : 17.3, foodNum: 9
name: Alice, bmi : 17.65, foodNum: 8

Person.foodNumと単にオブジェクトにプロパティを設定してあげているのがポイントです。 JavaScriptっぽいですね。JavaScriptに慣れてない人はなんだこの変態文法と思うはずです。
そんな人はES2015版を見てもらえばいいかもしれません。ただし、実運用で使う場合はBabelを忘れずに…。

ES2015版

const roundFloat = (number, n) => {
    const _pow = Math.pow( 10 , n );
    return Math.round( number * _pow ) / _pow;
}
(() => {
    // ES2015 Class
    class Person {
        constructor(name, height, weight) {
            this.name = name;
            this.height = height;
            this.weight = weight;
        }
        static foodNum = 10;  // static variable
        bmi() {
            if (!this.height || !this.weight) {
                return 0;
            }
            return roundFloat(this.weight / Math.pow(this.height / 100, 2), 2);
        }
        show() {
            console.log(`name: ${this.name}, bmi : ${this.bmi()}, foodNum: ${Person.foodNum}`);
        }
        eat() {
            if (Person.foodNum != 0) {
                Person.foodNum--;
                this.weight += 1;
            }
        }
    }
    const person1 = new Person('Bob', 180, 65);
    person1.show();
    person1.eat();
    person1.show();
    const person2 = new Person('Alice', 170, 50);
    person2.show();
    person2.eat();
    person2.show();
})();

さっきと同じです。ES5版のSyntax Sugarっすね。Java/C#っぽくなりました。TypeScriptだとなお近くなります。

ぼやき

JavaScriptとNode力が足りないのでたまにES5で書くとthis.hoge = function() {}と書かねばならないところを、
var foo = function() {}とやって自爆しまう雑魚でした。
ECMAScript 6 compatibility table を見ると、もう最近はIEを捨てると、ちょっとしたJSを書くときではBabeらずにES2015で書いてしまってもいいかもしれない…と思った。 JSの辛いところは古くからあるライブラリはやはりES5以前の知識が必須なところですかね。

参考リンク

Static variables in JavaScript - Stack Overflow