JavaScript初心者向け!関数、オブジェクト、メソッド書き方ガイド

js

JavaScript初心者が理解しにくい関数、オブジェクト、メソッドなどを紹介します。即時関数?無名関数?メソッド?書き方は?そういった疑問が解消できればと思います。他言語経験者だからこそハマるという場合にも役立つと思います。

いろいろ説明してますが内容は置いといて、こんな書き方(文法)があるんだなぁと知ってもらえれば幸いです。

スポンサーリンク

関数について

関数の宣言、実行方法など、見慣れない文法があります。順に説明します。

関数宣言

function add(x,y) {
  return x + y ;
}
alert( add(1,2) );  // 3が出力される

これは他言語と同様です。関数を定義し、関数名と引数を指定して呼び出します。

関数式

var calc = function add(x,y) { return x + y };
alert( calc(1,2) ); // 3が出力される

//以下の呼び出しはできない
alert ( add(1,2) ); // ReferenceError: add is not defined

関数定義を変数に代入しています。このような形式を関数式と呼びます。呼び出す際は、代入した変数に引数を付けて呼び出します。

関数定義にて関数名addとしていますが、add(1,2)と呼び出すことはできません。関数内で自分自身を呼び出す場合、関数名addを使用します。

無名関数

var calc = function (x,y) { return x + y };
alert( calc(1,2) ); // 3が出力される

関数式の関数名は省略できます。再帰関数以外は、関数名を付ける意味があまりないので、省略されることが多いです。

即時関数

// 即時実行される
var result = ( function add(x,y) { return x + y }(1,2) );
// 3が出力される
alert( result );

( function() { 処理 } (引数) );という形式で関数式の関数が即時実行されます。関数定義のあとの引数部分が呼び出しになります。全体を()でくくること、引数を()で指定することが条件です。この場合も無名関数にできます。引数がない場合、空の()で呼び出します。

var greeting = ( function () { return "hello!"}() );
alert( greeting ) // hello!と出力される。

即時関数と、変数に関数を代入する記述が似ているので混同しないように気をつけてください。

// 即時関数(関数の結果が変数に格納される)
var result = ( function add(x,y) { return x + y }(1,2) );

// この呼び出しはできない
result(1,2);  // TypeError: result is not a function

オブジェクト

オブジェクトとは、、、というのはうまく説明できないので、とにかく文法を覚えましょう。オブジェクトはプロパティの集まりです。プロパティとは関数や値などのことです。なんとなくの理解で大丈夫です。

初期化方法1(オブジェクト初期化子)

var obj = {}; //空のオブジェクトを作成

// personオブジェクトを作成
var person =  {
  name : "taro",
  age : 35,
  job : { business : "Web制作" ,      // 別のオブジェクトを入れ子
          category : "Webデザイナー",
        }
  }

変数名 = {プロパティ名:値}の形式で初期化できます。オブジェクトの中に別のオブジェクトを入れ子にできます。

初期化方法2(コンストラクタ関数)

以下二つの手順を踏みます。

  • コンストラクタ関数の定義
  • newを使用してオブジェクトをインスタンス化
// コンストラクタ関数を定義
function People (name , age , job) {
  this.name = name;
  this.age = age;
  this.job = job;
}

// newでインスタンス化
var person = new People ("taro", 35 , { business : "Web制作" , category : "Webデザイナー"});
alert (person.name);  // taroと出力

コンストラクタ関数名は先頭を大文字にすることが多いです。命名規約のようなものです。コンストラクタ関数内でthisキーワードを使って、引数を格納します。new コンストラクタ関数(引数)の形式でインスタンス化します。

プロパティへのアクセス(参照)

二つの方法があります。どちらでもいいのですが、プロパティ名にスペースを含む場合など、ブラケット表記法でしかアクセスできない場合もあります。

// ドット表記法
alert(person.name); // taroと出力
alert(person.job.business); // Web制作と出力

// ブラケット表記法
alert(person["name"]); // taroと出力

// プロパティへ代入
person.age = 20;

// 新しいプロパティを定義
person.hobby = "音楽";
person["like music"] = "J-POP"; // プロパティ名にスペース

メソッド

プロパティの中で関数定義をメソッドと呼びます。初期化やアクセス方法はこれまでのプロパティと同様です。

オブジェクト初期化子

// personオブジェクトを作成
var person =  {
  name : "taro",
  age : 35,
  job : {
    business : "Web制作" ,      // 別のオブジェクトを入れ子
    category : "Webデザイナー",
    },
  // メソッド
  dispName : function() {  
    alert(this.name); // thisで自身のプロパティを参照
  }
}

// メソッドを呼び出す(プロパティへアクセスと同義)
person.dispName();  // taroと出力

コンストラクタ関数

// コンストラクタ関数を定義
function People (name , age , job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.dispName = function() {
    alert(this.name);
  }
}

// newでインスタンス化
var person = new People (
    "taro",
    35,
    { business : "Web制作" , category : "Webデザイナー"}
  );

// メソッドを呼び出す
person.dispName();  // taroと出力

どちらの初期化方法もメソッド定義を無名関数で行っていますが、関数式で変数に代入したものでもできます。

myMethod = function() {
  alert(this.name);
}

var person =  {
  name : "taro",
  this.dispName = myMethod;
}

person.dispName();

// これも呼び出せてしまう
myMethod(); // this.nameが参照できないので、空のダイアログが出力される

ただしこの場合、personオブジェクトとは関係なく、myMethod()と呼び出すことができてしまいます。注意してください。

プロトタイプ

プロトタイプの説明の前に、コンストラクタ関数のおさらいです。コンストラクタ関数でプロパティを定義してnew(インスタンス化)することで、コンストラクタ関数内のプロパティが生成されます。

// コンストラクタ関数を定義
function People (name) {
  this.name = name;
  this.dispName = function() {
    alert(this.name);
  }
}

obj1 = new People("taro")
obj1.dispName();    // taroと出力

obj2 = new People("hanako")
obj2.dispName();    // hanakoと出力

このとき、プロパティnameはインスタンスごとに変わりますが、表示する関数は同じです。同じなのに、インスタンス化するたびに関数が生成されるのは無駄です。おそらく、メモリ上にobj1.dispName()とobj2.dispname()が別々に存在しているはずです。(間違ってたらツッコミください)

この問題を解決するのがプロトタイプです。先ほどのコンストラクタを少し修正します。

// コンストラクタ関数を定義
function People (name) {
  this.name = name;
}
// プロトタイプを定義
People.prototype.dispName = function() {
  alert(this.name);
}

obj1 = new People("taro")
obj1.dispName();    // taroと出力

obj2 = new People("hanako")
obj2.dispName();    // hanakoと出力

出力結果は同じです。

コンストラクタ関数名.prototype.プロパティ名で定義できます。関数定義をコンストラクタ関数から外に出したことで、インスタンス化するたびに生成されなくなりました。プロトタイプは各インスタンスからアクセスできます。

その他

他にもわかりにくいものを記載します。

変数の多重代入

var a = b = 1;
alert(a + b); // 2と出力

a = 2;
alert(a + b); // 3と出力

同じ値を複数変数に代入できます。

var obj1 = obj2 = {}; // 空のオブジェクトを定義
obj1.name = "taro";

alert(obj1.name); // taroと出力
alert(obj2.name); // taroと出力(なぜ?)

obj2.name = "hanako";

alert(obj1.name); // hanakoと出力(なぜ?)
alert(obj2.name); // hanakoと出力

オブジェクトの場合、注意が必要です。お互いに参照されている状態なので、片方のオブジェクトプロパティに設定するともう一方でも同じ値となります。ちょっと表現が適切でないかもですが、概念を押さえてください。

クロージャ

以下のソースはMDNより引用。

function init() {
  var name = "Mozilla"; // name は、init が作成するローカル変数

  function displayName() { // displayName() は内部に閉じた関数
    alert(name); // 親関数で宣言された変数を使用
  }
  displayName();
}

関数を入れ子にできます。意味があるのですが、ここでは紹介にとどめます。詳細はリンク元をご参照ください。

まとめ

いかがでしょうか。ややこしいですね。個別の内容を覚えたり使ったりするかは置いといて、誰かが書いたソースを読み解くときにわからない文法が出てきた際に参考になればと思います。

JavaScriptは言語仕様、複数ライブラリを読み込むことなどにより、安全なコーディングをするには、テクニカルになってしまうようです。テクニカルさと可読性の両立に気を配りたいと思います。

スポンサーリンク

この記事が気に入っていただけたらシェアお願いします。励みになります。

関連記事はありませんでした

prev PHPのfile_get_contents(cURL)がリダイレクトループする場合の対応方法 next WordPressを高速化!PageSpeed Insightsで高得点を目指す方法

コメントをどうぞ

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です