atwiki-logo
  • 新規作成
    • 新規ページ作成
    • 新規ページ作成(その他)
      • このページをコピーして新規ページ作成
      • このウィキ内の別ページをコピーして新規ページ作成
      • このページの子ページを作成
    • 新規ウィキ作成
  • 編集
    • ページ編集
    • ページ編集(簡易版)
    • ページ名変更
    • メニュー非表示でページ編集
    • ページの閲覧/編集権限変更
    • ページの編集モード変更
    • このページにファイルをアップロード
    • メニューを編集
    • 右メニューを編集
  • バージョン管理
    • 最新版変更点(差分)
    • 編集履歴(バックアップ)
    • アップロードファイル履歴
    • ページ操作履歴
  • ページ一覧
    • ページ一覧
    • このウィキのタグ一覧
    • このウィキのタグ(更新順)
    • このページの全コメント一覧
    • このウィキの全コメント一覧
    • おまかせページ移動
  • RSS
    • このウィキの更新情報RSS
    • このウィキ新着ページRSS
  • ヘルプ
    • ご利用ガイド
    • Wiki初心者向けガイド(基本操作)
    • このウィキの管理者に連絡
    • 運営会社に連絡(不具合、障害など)
ページ検索 メニュー
とりあえず雑記帳(跡地)
  • ウィキ募集バナー
  • 目安箱バナー
  • 操作ガイド
  • 新規作成
  • 編集する
  • 全ページ一覧
  • 登録/ログイン
ページ一覧
とりあえず雑記帳(跡地)
  • ウィキ募集バナー
  • 目安箱バナー
  • 操作ガイド
  • 新規作成
  • 編集する
  • 全ページ一覧
  • 登録/ログイン
ページ一覧
とりあえず雑記帳(跡地)
ページ検索 メニュー
  • 新規作成
  • 編集する
  • 登録/ログイン
  • 管理メニュー
管理メニュー
  • 新規作成
    • 新規ページ作成
    • 新規ページ作成(その他)
      • このページをコピーして新規ページ作成
      • このウィキ内の別ページをコピーして新規ページ作成
      • このページの子ページを作成
    • 新規ウィキ作成
  • 編集
    • ページ編集
    • ページ編集(簡易版)
    • ページ名変更
    • メニュー非表示でページ編集
    • ページの閲覧/編集権限変更
    • ページの編集モード変更
    • このページにファイルをアップロード
    • メニューを編集
    • 右メニューを編集
  • バージョン管理
    • 最新版変更点(差分)
    • 編集履歴(バックアップ)
    • アップロードファイル履歴
    • ページ操作履歴
  • ページ一覧
    • このウィキの全ページ一覧
    • このウィキのタグ一覧
    • このウィキのタグ一覧(更新順)
    • このページの全コメント一覧
    • このウィキの全コメント一覧
    • おまかせページ移動
  • RSS
    • このwikiの更新情報RSS
    • このwikiの新着ページRSS
  • ヘルプ
    • ご利用ガイド
    • Wiki初心者向けガイド(基本操作)
    • このウィキの管理者に連絡
    • 運営会社に連絡する(不具合、障害など)
  • atwiki
  • とりあえず雑記帳(跡地)
  • JavaScript
  • Functionオブジェクトあれこれ

とりあえず雑記帳(跡地)

Functionオブジェクトあれこれ

最終更新:2011年11月15日 23:01

Bot(ページ名リンク)

- view
管理者のみ編集可
WebコミックLibraryhttp://web-comi.appspot.com/
GAE/JとSlim3で作成してみた、各出版社から配信されているWebコミックをまとめて閲覧できるサイトです。只今、実験運用中…


JavaScriptでは関数もオブジェクト(Functionオブジェクト)


functionステートメント

  • 通常、JavaScriptで関数を定義する場合に用いる。
  • あまり、Functionオブジェクトとかは意識してないかと思います。意識しなくても良い関数の定義方法。
// 定義
function foo() {
    alert("test");
}
 
// 呼び出し
foo();
 


function演算子とfunction式

  • function演算子によって、Functionオブジェクトが生成される
    • function演算子の後に、生成するFunctionオブジェクトの、関数の定義を記述します(Functionオブジェクトのリテラル表現)。
      • ぱっと見た目はfunctionステートメントと変わりませんな。
      • 特徴的なのは、関数名が無いことです※実際は記述できるらしいですが、滅多に記述しません
  • 結果がFunctionオブジェクトへの参照(以下「への参照」は省略)となる式を「function式」と呼ぶ。
    • function演算子を用いた、Functionオブジェクトのリテラル表現もfunction式
    • Functionオブジェクトを代入した変数のみで表される式もfunction式

/* Stringオブジェクトの場合 */
// リテラル表現"test"が表すStringオブジェクトが、strに設定される。
var str = "test";
 
/* Functionオブジェクトの場合 */
// リテラル表現function(){...}が表すFunctionオブジェクトが、func1に設定される。
var func1 = function() {
    alert("test");
};
 
// 引数がある場合
var func2 = function(arg) {
    alert(arg);
};
 


functionステートメントの再解釈

  • 実は、functionステートメントとは
    • 記述された内容のFunctionオブジェクトを生成し
    • グローバルオブジェクトに関数名と同名のプロパティを定義し
    • そのプロパティに生成したFunctionオブジェクトを設定する、という一連の動作を行う「ステートメント」です
    • つまり、「function式」では無いことに注意(後ほど説明)


functionオブジェクトの処理実行

  • Functionオブジェクトに対して"()"を適用することで、関数を実行する。
  • つまり、function式に対して()を適用する

/* Stringオブジェクトの場合 */
var str = "test";
alert(str.length); // strが参照するStringオブジェクトの、lengthプロパティへのアクセス
alert("test".length); // リテラル表現に対して、直接プロパティを参照してもよい
 
/* Functionオブジェクトの場合 */
var func1 = function() {
    alert("test");
};
func1();  // func1が参照するFunctionオブジェクトが表す処理を実行する。
 
(
function() {
    alert("test");
}
)();  // リテラル表現に対して、直接()を適用して処理を実行してもよい。
 
// 引数がある場合
var func2 = function(arg) {
    alert(arg);
};
func2("test");  // func2が参照するFunctionオブジェクトが表す処理を実行する。
 
(
function(arg) {
    alert(arg);
}
)("test");  // リテラル表現に対して、引数を指定した()を直接適用して処理を実行してもよい。
 

  • Functionオブジェクトのリテラル表現を直接実行する場合にリテラル表現を丸括弧で囲んでいるのは、丸括弧で囲まないとリテラル表現(=function式)では無く「functionステートメント」と解釈されてしまうためです。「functionステートメント」はFunctionオブジェクトを表しているわけではないので、()を適用できません。


Functionオブジェクトをやりとり

  • Functionオブジェクトは、当然関数の引数や戻り値として使えます。
function bar(func) {
    func();
}
 
var foo = function() {
    alert("test");
};
 
bar(foo);
 
  • 上記の例では、"test"をalert表示するFunctionオブジェクトを生成し、それを関数barに渡しています。
  • 関数barは、引数funcに渡されたFunctionオブジェクトを、引数なしで呼び出します。
    • 渡されたFunctionオブジェクトが要求する引数と、実際に呼び出すときの引数は一致しなくても大丈夫っぽいです。

function foo() {
    return function() {
        alert("test");
    };
}
 
var func = foo();
 
func();
 
  • 上記の例では、"test"をalert表示するFunctionオブジェクトを戻り値として返す関数fooを、functionステートメントで定義しています。
  • 戻り値を受け取った後、()を適用して呼び出しています。


クロージャ

  • 下記のケースを考えます。
function foo(arg) {
    var val = "123";
    return function(str) {
        alert(val + arg + str);
    };
}
 
var func = foo("456");
 
func("789");
 
  • この例では、関数foo()内部で生成したFunctionオブジェクトが、function式の外側で宣言されている変数valや引数argを参照しています。またFunctionオブジェクト自身で引数strを定義しています。
    • foo()はFunctionオブジェクトを返しますが、Functionオブジェクト「だけ」では、Functionオブジェクト自身で定義していないvalやargの値を決定できません。
    • そこで、通常はfoo()終了後に削除されるvalやargのメモリ領域は、function式で参照された場合は削除されず、それを参照するFunctionオブジェクトが削除されるまで存在します。
  • このような、「関数(Functionオブジェクト)と、関数(Functionオブジェクト)自身で定義されていない変数(argとval)のメモリ領域」の組み合わせを「クロージャ」と呼びます。
    • クロージャの「環境」とは、JavaScriptにおいては、argやvalのメモリ領域を指します。
    • 別に「定義外の変数のメモリ領域を保持しているものだけがクロージャ」ってわけでもありません。「定義外の変数を参照していない=0個の変数のメモリ領域を確保している」と解釈すれば、メモリ領域を保持していなくてもクロージャです。
    • まぁJavaScript的には要するに、Functionオブジェクト≒クロージャと考えておいてもいいです。

  • foo()の呼び出し毎に、ローカル変数のメモリ領域は異なるものが割り当てられるので、foo()が返すクロージャのargやvalのメモリ領域(環境)も、foo()の呼び出し毎に異なります。
function foo(arg) {
    var val = "123";
    return function(str) {
        alert(val + arg + str);
    };
}
 
var func1 = foo("456"); // func1のargは"456"になる
var func2 = foo("abc"); // func2のargは"abc"になる
// valもメモリ領域は別物だが、内容は同じ"123"が設定されている
 
func1("789");
func2("def");
 

お堅い説明

  • 関数で参照している変数は「束縛変数」と「自由変数」に分類されます。
    • 厳密な定義はよくわからないので、不正確かもしれませんが、
      • 束縛変数とは、(引数を含め)関数自身で定義している変数(上記のstr)
      • 自由変数とは、関数自身では定義されていない変数(上記のargやval)
  • 関数が実行可能であるためには、関数内の全変数が束縛されている(値が設定されることが保証されている)必要があります。
    • 束縛変数は、既に関数自身の定義によって束縛されています(引数として値が外部から渡される、ローカル変数として値が代入される等)。
    • 自由変数は、関数自身では定義されていないため、関数自身の定義だけでは何の値が設定されるかわかりません。
  • そこで、関数に対して、その関数の自由変数の値を定義するのが環境です。
    • 関数に対して環境を与えることで、関数の自由変数を束縛します(自由変数の値を定数化する)。
    • ということで、関数と環境のペアをクロージャと呼びます。
  • 同じ関数でも、環境が異なれば、返す結果も異なります。
    • 関数と環境の関係は、アプリケーションと環境変数の関係と、まさに同じと考えてください。


thisが指すもの

  • 関数内で用いるthisキーワードが何を指すか
var func = function() {
    alert(this.bar);
};
 
  • Javaとかに慣れていると、関数もオブジェクトということから、thisは生成されたFunctionオブジェクト自身を指すと勘違いしそうですが、違うのです

  • thisが指すのは、関数が実行された際に指定されたコンテキストオブジェクト
    • コンテキストオブジェクトを指定する方法は幾つかある
    • 代表的なのは、関数オブジェクトを指すプロパティに対して()を適用した場合は、そのプロパティを持つオブジェクトがコンテキストに選ばれる
      • 文章で書くと回りくどいが、要するに下記のような、ありきたりな方法
var obj1 = new Object(); // オブジェクトを生成
obj1.bar = "obj1"; // オブジェクトにbarプロパティを定義して、文字列を設定
obj1.func = function() { // オブジェクトにfuncプロパティを定義して、Functionオブジェクトを設定
    alert(this.bar);
};
 
obj1.func(); // オブジェクトのfuncプロパティに設定されたFunctionオブジェクトを実行(コンテキストオブジェクトとしてobj1が選ばれる)
 
    • つまり、同じ関数オブジェクトでも、コンテキストオブジェクトが違えば、thisが指すオブジェクトも違う
var func = function() { // Functionオブジェクト生成
    alert(this.bar);
};
 
var obj1 = new Object(); // オブジェクト1を生成
obj1.bar = "obj1";
var obj2 = new Object(); // オブジェクト2を生成
obj2.bar = "obj2";
 
obj1.foo = func;
obj1.foo(); // コンテキストオブジェクトはobj1
 
obj2.foo = func;
obj2.foo(); // コンテキストオブジェクトはobj2
 

  • functionステートメントで生成したFunctionオブジェクトのthisが指すのは?
    • functionステートメントによって、グローバルオブジェクトのプロパティに設定されるので、コンテキストオブジェクトはグローバルオブジェクトになる

applyメソッド

  • コンテキストオブジェクトを指定する別な方法として、Functionオブジェクトのapply()メソッドを用いる方法があります
var obj1 = new Object();
obj1.bar = "obj1";
 
var func = function(arg1, arg2) {
    alert(this.bar + ":" + arg1 + ":" + arg2);
};
 
func.apply(obj1, ["abc", "123"]);
 
  • apply()メソッドを呼ぶと、そのFunctionオブジェクトが表す関数が実行されます。
  • 第1引数に、実行時のコンテキストオブジェクトとするオブジェクトを指定します。
  • 本来の関数の引数は、apply()メソッドの第2引数に、配列で指定します。


new演算子とコンストラクタ

見た目はJavaと同じでも、仕組みは全然別物なので要注意

  • new演算子を使うと、新しいオブジェクトを生成できます。
var obj = new Object();
var str = new String();
var dt = new Date();
 
  • JavaScriptにはクラスが存在していないわけですが、ではnew演算子の後に指定しているのは何でしょう?
  • 実は、Functionオブジェクトを指定しているのです。
var Foo = function() {
    this.bar = "test";
}
 
var obj = new Foo();
 
alert(obj.bar);
 
  • オブジェクトが生成される際に、オブジェクトを初期化するための関数として、new演算子の後に指定したFunctionオブジェクトが実行されます。
  • 実行されるFunctionオブジェクトのコンテキストオブジェクトは、new演算子で新しく生成したオブジェクトになります。
    • new演算子で生成されるオブジェクトは常に、(既定のプロパティ以外は)何もプロパティを持たない、プレーンなオブジェクトです。
    • そのプレーンなオブジェクトをコンテキストオブジェクトとして、Functionオブジェクトの実行時にプロパティを定義していきます。
  • つまりは、生成したオブジェクトのコンストラクタの役割をするFunctionオブジェクトをnew演算子の後に指定しているのです。

  • コンストラクタとして指定したFunctionオブジェクトには、生成したオブジェクトのconstructorプロパティでアクセスできます。
var Foo = function() {
    this.bar = "test";
}
 
var obj = new Foo();
 
alert(obj.constructor);
 


プロトタイプチェーンによる、プロパティの共有

  • JavaScriptでは通常、プロパティはオブジェクト毎に、動的に定義します。
  • 例えば、Functionオブジェクトのプロパティfooを、複数のオブジェクトに設定する場合は、
var func = function() {
    alert(this.bar);
}
 
var obj1 = new Object();
obj1.foo = func;
obj1.bar = "obj1";
var obj2 = new Object();
obj2.foo = func;
obj2.bar = "obj2";
 
obj1.foo();
obj2.foo();
 
  • オブジェクトが多い場合に、これをオブジェクトを生成する度にやるのは面倒くさいですね。
  • 例えば、先に説明した、コンストラクタ内でプロパティを設定する方法がありそうです。
var Foo = function() {
    this.foo = function() {
        alert(this.bar);
    }
}
 
var obj1 = new Foo();
obj1.bar = "obj1";
var obj2 = new Foo();
obj2.bar = "obj2";
 
obj1.foo();
obj2.foo();
 
  • ところがこの方法では、オブジェクト毎にFunctionオブジェクトも生成することになり、メモリ効率はよろしくありません。
  • そこで、JavaScriptにはプロトタイプチェーンという、プロパティを複数のオブジェクト間で共有する仕組みが用意されています。

プロトタイプチェーンを詳しく

  • JavaScriptのオブジェクトは全て、内部プロパティ__proto__を持ちます
    • なお、__proto__を直接利用することは推奨されていません。IEでは外部からアクセスすらできません。
obj.foo();
  • 上記のような、オブジェクトのプロパティfoo(fooはFunctionオブジェクトとする)にアクセスする際に
    • まず、指定したobjに対して、プロパティfooが定義されているか検索
    • objにプロパティfooが定義されていない場合は、obj.__proto__に設定されたオブジェクトに対して、プロパティfooが定義されているか検索
    • obj.__proto__にプロパティfooが定義されていない場合は、obj.__proto__.__proto__に設定されたオブジェクトに対して、プロパティfooが定義されているか検索
    • 以降、同様にして、プロパティfooが見つかるか、__proto__がnullになるまで、__proto__を遡っていきます
  • このような、指定されたプロパティの検索対象となる、内部プロパティ__proto__の連鎖構造をプロトタイプチェーンと呼びます。
  • つまり、__proto__に同じオブジェクトが設定されているオブジェクト同士は、__proto__に設定されたオブジェクト(と、そのプロトタイプチェーン)のプロパティを共有することになります。

  • では、__proto__に設定されているのは何者か?
  • __proto__に設定されてるのは、そのオブジェクト生成時のコンストラクタとなったFunctionオブジェクトの、プロパティprototypeが指すオブジェクトです。
    • Functionオブジェクトは全て、プロパティprototypeを持ちます。
    • Functionオブジェクト作成時には、prototypeにはプレーンなオブジェクト(new Object()で返されるオブジェクト)が設定されます。
    • prototypeに設定されたオブジェクトに対して、共有したいプロパティを定義していけば、そのFunctionオブジェクトをコンストラクタとして生成されたオブジェクトは、そのプロパティを共有することになります。
var Foo = function() {
}
 
Foo.prototype.foo = function() { // 共有したいプロパティfooをprototypeのオブジェクトに定義する
    alert("test");
}
 
var obj1 = new Foo(); // ここで、obj1.__proto__にFoo.prototypeが設定される
obj1.foo(); // obj1にはプロパティfooは定義されていないが、obj1.__proto__にあるFoo.prototypeにプロパティfooが定義されているため、実行可能。
 
var obj2 = new Foo();
obj2.foo(); // obj1と同じFooをコンストラクタとして生成されたobj2からも、fooを実行可能
 

  • プロトタイプチェーン上で発見されたプロパティが参照する、Functionオブジェクトを実行する際のコンテキストオブジェクトは、最初にプロパティのアクセスを試みたオブジェクトになります。
    • 実際にそのプロパティが定義されている、prototypeのオブジェクトではないことに注意
var Foo = function() {
    this.bar = "test";
}
 
Foo.prototype.foo = function() {
    alert(this.bar);
}
 
var obj = new Foo();
 
obj.foo(); // foo()のコンテキストオブジェクトはobj
 
  • この、最初にプロパティのアクセスを試みたオブジェクトがコンテキストオブジェクトになる仕組みを利用して、クラスもどきが実現できます
    • →JavaScriptでクラスもどき
「Functionオブジェクトあれこれ」をウィキ内検索
LINE
シェア
Tweet
とりあえず雑記帳(跡地)
記事メニュー

メニュー

  • トップページ
  • コメント
  • とりあえずインターフェース入門
  • Yesod
  • Haskell
  • Slim3
  • JavaScript
  • Google App Engine
  • Android
  • Facebook
  • GWT
  • OpenSocial
  • Struts 2
  • Subversion
  • Apache
  • JSONIC
  • Flex

  • WebコミックLibraryについて

公式サイト

  • Yesod
  • Haskell
  • Slim3
  • JavaScript - MDN
  • App Engine for Java
  • Android Developers
  • Google Web Toolkit
  • Struts
  • OpenSocial
  • OSDE

  • ToDo

ここを編集
記事メニュー2
間違いの御指摘は
コメントまでm(_ _)m

更新履歴

取得中です。


ここを編集

総数: -
本日: -
昨日: -
人気記事ランキング
  1. Slim3/とりあえずSlim3アプリケーションを作ろう/Controllerで画面作成
  2. Struts 2
もっと見る
最近更新されたページ
  • 4400日前

    Haskell
  • 4400日前

    Yesod
  • 4400日前

    トップページ
  • 4510日前

    メニュー
  • 4511日前

    Struts 2
  • 4537日前

    コメント
  • 4706日前

    Google App Engine
  • 4743日前

    Slim3/環境構築とプロジェクト作成
  • 4768日前

    Google App Engine/キャッシュの計画
  • 4778日前

    Slim3/文字列の部分一致検索とページング
もっと見る
人気記事ランキング
  1. Slim3/とりあえずSlim3アプリケーションを作ろう/Controllerで画面作成
  2. Struts 2
もっと見る
最近更新されたページ
  • 4400日前

    Haskell
  • 4400日前

    Yesod
  • 4400日前

    トップページ
  • 4510日前

    メニュー
  • 4511日前

    Struts 2
  • 4537日前

    コメント
  • 4706日前

    Google App Engine
  • 4743日前

    Slim3/環境構築とプロジェクト作成
  • 4768日前

    Google App Engine/キャッシュの計画
  • 4778日前

    Slim3/文字列の部分一致検索とページング
もっと見る
ウィキ募集バナー
新規Wikiランキング

最近作成されたWikiのアクセスランキングです。見るだけでなく加筆してみよう!

  1. 鹿乃つの氏 周辺注意喚起@ウィキ
  2. 機動戦士ガンダム EXTREME VS.2 INFINITEBOOST wiki
  3. MadTown GTA (Beta) まとめウィキ
  4. R.E.P.O. 日本語解説Wiki
  5. AviUtl2のWiki
  6. シュガードール情報まとめウィキ
  7. ソードランページ @ 非公式wiki
  8. ドラゴンボール Sparking! ZERO 攻略Wiki
  9. シミュグラ2Wiki(Simulation Of Grand2)GTARP
  10. 星飼いの詩@ ウィキ
もっと見る
人気Wikiランキング

atwikiでよく見られているWikiのランキングです。新しい情報を発見してみよう!

  1. アニヲタWiki(仮)
  2. ストグラ まとめ @ウィキ
  3. ゲームカタログ@Wiki ~名作からクソゲーまで~
  4. 初音ミク Wiki
  5. 機動戦士ガンダム バトルオペレーション2攻略Wiki 3rd Season
  6. 検索してはいけない言葉 @ ウィキ
  7. オレカバトル アプリ版 @ ウィキ
  8. 発車メロディーwiki
  9. Grand Theft Auto V(グランドセフトオート5)GTA5 & GTAオンライン 情報・攻略wiki
  10. 英傑大戦wiki
もっと見る
全体ページランキング

最近アクセスの多かったページランキングです。話題のページを見に行こう!

  1. 過去の行動&発言まとめ - 鹿乃つの氏 周辺注意喚起@ウィキ
  2. マイティーストライクフリーダムガンダム - 機動戦士ガンダム EXTREME VS.2 INFINITEBOOST wiki
  3. 参加者一覧 - ストグラ まとめ @ウィキ
  4. 前作からの変更点 - 機動戦士ガンダム EXTREME VS.2 INFINITEBOOST wiki
  5. 旧トップページ - 発車メロディーwiki
  6. 魔獣トゲイラ - バトルロイヤルR+α ファンフィクション(二次創作など)総合wiki
  7. マリオカート ワールド - アニヲタWiki(仮)
  8. コメント/雑談・質問 - マージマンション@wiki
  9. フェイルノート - 機動戦士ガンダム バトルオペレーション2攻略Wiki 3rd Season
  10. RqteL - ストグラ まとめ @ウィキ
もっと見る

  • このWikiのTOPへ
  • 全ページ一覧
  • アットウィキTOP
  • 利用規約
  • プライバシーポリシー

2019 AtWiki, Inc.