LoginSignup
0
1

More than 5 years have passed since last update.

JavaScriptのPrivateプロパティを試作してみた

Last updated at Posted at 2017-10-31

はじめに

古いJavaScriptではオブジェクトのプライベート変数(プロパティ)を持つのが難しいのでクロージャーを使って実装します。書き方をよく忘れてしまうのでメモしておきます。

ESなんとかの新しいJSだともっと書きやすいとは思いますが、元々のJavaScriptではどうなっているのか、というところの勉強としての記事なのでESなんとかは対象外です。

コード説明

下記コードでは、newを使う使わない、どちらでもオブジェクトを生成できるPoint型を定義しています。

  • main01 は通常のオブジェクトの生成方法。これだと、プライベートプロパティを持つことができません。

  • main02 はクロージャー使って、_xと_yをオブジェクトに固定して持っているので、プライベートプロパティを持つことができます。アクセスメソッドをオブジェクトに定義しています。
    このアクセスメソッドは、prototypeでは宣言できません。

  • main03 は、試しにアクセスメソッドをprototypeにて定義してみました。誤動作するのがわかります。

index.js

"use strict";

var main01 = function () {

  var Point = function(x, y) {
    if (!(this instanceof Point)) {
      return new Point(x, y);
    }
    this._x = x;
    this._y = y;
  };

  Point.prototype.x = function() {
    return this._x;
  };

  Point.prototype.y = function() {
    return this._y;
  };

  Point.prototype.distance = function(point) {
    return Math.sqrt(
      Math.pow(point.x() - this._x, 2) +
      Math.pow(point.y() - this._y, 2) );
  };

  var p1 = Point(0,0);
  var p2 = Point(1,1);
  alert(p1.distance(p2).toString());  //1.4142135623730951
  alert(p2._x);                       //1

  var p3 = Point(0,0);
  var p4 = Point(1,1);
  alert(p3.distance(p4).toString());  //1.4142135623730951
  alert(p4._x);                       //1
};

var main02 = function () {

  var Point = function(_x, _y) {
    if (!(this instanceof Point)) {
      return new Point(_x, _y);
    }

    this.x = function() {
      return _x;
    };

    this.y = function() {
      return _y;
    };

    Point.prototype.distance = function(point) {
      return Math.sqrt(
        Math.pow(point.x() - this.x(), 2) +
        Math.pow(point.y() - this.y(), 2) );
    };
  };

  var p1 = new Point(0,0);
  var p2 = new Point(1,1);
  alert(p1.distance(p2).toString());  //1.4142135623730951
  alert(p2._x);                       //undefined

  var p3 = Point(0,0);
  var p4 = Point(1,1);
  alert(p3.distance(p4).toString());  //1.4142135623730951
  alert(p4._x);                       //undefined
};


var main03 = function () {

  var Point = function(_x, _y) {
    if (!(this instanceof Point)) {
      return new Point(_x, _y);
    }

    Point.prototype.x = function() {
      return _x;
    };

    Point.prototype.y = function() {
      return _y;
    };

    Point.prototype.distance = function(point) {
      return Math.sqrt(
        Math.pow(point.x() - this.x(), 2) +
        Math.pow(point.y() - this.y(), 2) );
    };
  };

  var p1 = Point(0,0);
  var p2 = Point(1,1);
  alert(p1.distance(p2).toString());  //0
  alert(p2._x);                       //undefined

  var p3 = Point(0,0);
  var p4 = Point(1,1);
  alert(p3.distance(p4).toString());  //0
  alert(p4._x);                       //undefined
};

var main = function() {
  main01();
  main02();
  main03();
};

動作確認は下記のindex.htmlで行いました。

WSH JScriptでも動くように index.wsf も作りました。

index.html
<!DOCTYPE html>
<html lang="ja"><head>
  <meta charset="utf-8">
  <script src="./index.js"></script>

<script>

document.addEventListener("DOMContentLoaded",function(eve){
    main();
},false);

</script>

</head><body>
</body></html>
index.wsf
<?xml version="1.0" encoding="shift-jis" ?>
<job>
    <script language="JavaScript" src=".\index.js"></script>
    <script language="JavaScript">
    <![CDATA[

var alert = function (message) {
  if (typeof message === 'undefined') {
    WScript.Echo('undefined');
  } else {
    WScript.Echo(message);
  }
};

main();

    ]]>
    </script>
</job>

結果

プライベートプロパティはアクセスメソッドがprototypeではなく作らなければならないので、やや不便です。
オブジェクトごとにメソッドを定義するのは、何十何百とオブジェクトを生成するときに無駄が多いです。
JSは負荷(何百というオブジェクト生成などなど?よくわからないけれども)をかけると原因不明でブラウザ上で止まるときがあり、そのようなことはなるべく避けたいので、この書き方(main02のやり方)は推奨しません。

単純にアンダーバーを付属したプロパティとして作り、利用者側に「使わないでください」と示す程度の方(main01のやり方)がいいと感じます。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1