例えば次のような処理を考えてみます。
名前と身長と体重を与えると、その人の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以前の知識が必須なところですかね。