0
0

More than 3 years have passed since last update.

JavaScript で new する関数を prototype ごと巻き上げする

Last updated at Posted at 2019-11-02

注意

ここに書く内容は個人のノウハウのメモです。
使用する環境や職場によってはバッドノウハウになる可能性があります。

また、内容的には ES5 までを想定しています。


javascript では、function xxx(){} の形で書いた関数は、どこに書いてもいい。
コードの下に書いても、上でその関数を実行できる。

hello("Takashi"); //<- Hello, Takashi!

function hello(name) {
  alert("Hello, " + name + "!");
}

いわゆる「関数の巻き上げ」の挙動で、 javascript の入門本などにはたいてい
「コードが理解しづらくなるので、関数はコードの先頭で宣言するように」と書かれている。

けれども自分の場合は、メイン処理だけをコードの先頭にまとめられるので、意図的によく使う。
(ExtendScript 使いなので、関数部分だけコピペで使用したくなる事が多いせいかも)

で、newしてオブジェクトのインスタンスを生成するタイプの関数を使いたいとする。

var greeting = new Hello("Takashi");
greeting.func(); //<- Hello, Takashi!

function Hello(name) {
    this.name = name;
    this.func = function() {
        alert("Hello, " + this.name + "!");
    }
}

このように、 this を使って func 部分を書くならば、 function より上で実行できる。
ただしこの場合、 new するたびに func を生成するので
繰り返し利用するのならそのたび別関数を作っていて、処理負荷的に面白くない。

prototype を使って Hello の関数を宣言すれば、
何度 Hello インスタンスを生成しても、複数のインスタンスで func を共有することになる。
その方法で書いてみる。

var greeting = new Hello("Takashi");
greeting.func(); //<- Uncaught TypeError: greeting.func is not a function

function Hello(name) {
    this.name = name;
}
Hello.prototype.func = function() {
    alert("Hello, " + this.name + "!");
}

下に書いた Hello.prototype.func は、functionより上では利用できない。
巻き上げられるのは function Hello(name) {} の部分だけで、
Hello.prototype.func = function(){} の部分は下で実行されることになるから
prototypeが追加されていないHelloをnewすることになってしまう。

下にコピペできるnew用関数を作りたい。
いろいろやっているうちに、こんな風に書くようになった。

var greeting = new Hello("Takashi");
greeting.func(); //<- Hello, Takashi!

function Hello(name) {
    this.name = name;
    for (var _key in Hello.prototype) break;
    if (!_key) {
        Hello.prototype.func = function () {
            alert("Hello, " + this.name + "!");
        }
    }
}

Hello が new されたとき、 Hello が prototype を持っていなければ、 prototype を自己定義する。
2回目に new された時点では Hello はすでに prototype を持っているので、 prototype はインスタンスで共有になる。

function のブロック内に書いているので、 prototype 生成部分は一緒に巻き上げられるようになった。

追記 2019/11/04

こういう風にオブジェクトで prototype を書くと失敗する。

var greeting = new Hello("Takashi");
greeting.func(); //<- Uncaught TypeError: greeting.func is not a function

function Hello(name) {
    this.name = name;
    for (var _key in Hello.prototype) break;
    if (!_key) {
        Hello.prototype = {
            func: function () {
                alert("Hello, " + this.name + "!");
            },
            func2: function () {
                alert("Good morning, " + this.name + "!");
            }
        }
    }
}

Hello.prototype は空の状態で既に存在していて、
実行後はそれをオブジェクトごと置き換えはできないということみたい。
既にある Hello.prototype にひとつづつ設定する必要がある。

var greeting = new Hello("Takashi");
greeting.func(); //<- //<- Hello, Takashi!

function Hello(name) {
    this.name = name;
    for (var _key in Hello.prototype) break;
    if (!_key) {
        var prototype = {
            func: function () {
                alert("Hello, " + this.name + "!");
            },
            func2: function () {
                alert("Good morning, " + this.name + "!");
            }
        }
        for(var k in prototype) {
            Hello.prototype[k] = prototype[k];
        }
    }
}
0
0
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
0