JavaScript には call と apply というメソッドがありますが、両者の違いを説明してくれている情報を元に、自分なりに分かりやすくまとめてみました。
いきなり結論から
call と apply の違いは引数の書き方だけ。2番目以降の引数が連続した引数のリストか、引数の配列を一つだけ受け取るか。
だそうです(笑)
言葉で理解することは簡単なのですが、このままでは使用用途が明確ではないので、実際にサンプルコードをみながら次のような順で、両者の違いを詳しく見ていきたいと思います。
説明の概要
- call と apply の概要とその役割
- call について
- apply について
- まとめ
call と apply の概要とその役割
そもそも call や apply はどういったメソッドなのでしょうか。
以下のサンプルコードでは、sample_c インスタンスからそれぞれ apply と call を使って sample_b を呼び出し実行しています。このサンプルコードの場合は call も apply も同じ動きをします。
サンプルコード
[code]
function SampleA() {
this.word = ‘hello!’;
this.say = function() {
console.log(this.word);
}
}
function SampleB() {
this.word = ‘good-bye!’;
}
var sample_a = new SampleA();
var sample_b = new SampleB();
var sample_c = sample_a.say;
sample_a.say();
sample_c.apply(sample_b);
sample_c.call(sample_b);
[/code]
結果
[code]
hello!
good-bye!
good-bye!
[/code]
このように、apply や call を使えば、コンストラクタのメンバ変数を、あらゆる場所から呼び出すことが出来るようになります。
call について
call の概要
[code]
method.call(thisArg[, arg1[, arg2[, …]]])
[/code]
thisArg は method の this パラメータとして使われる値。thisArg を null か undefined とすると、グローバルオブジェクト(Window)となる。arg1, arg2,… は method に渡される引数。
サンプルコード
[code]
function Person(name,age) {
this.name = name;
this.age = age;
return this;
}
function Men(name, age) {
Person.call(this, name, age);
this.sex = ‘male’;
}
function Women(name, age) {
Person.call(this, name, age);
this.sex = ‘female’;
}
var father = new Men(‘Taro’, 45);
var mother = new Women(‘Hanako’, 35);
console.log(father.name);
console.log(father.age);
console.log(father.sex);
console.log(mother.name);
console.log(mother.age);
console.log(mother.sex);
[/code]
結果
[code]
Men
Women
Taro
45
male
Hanako
35
female
[/code]
this は自身のオブジェクト Men Women を指し、Men Women からそれぞれ Person を call で呼び出し、name, age を引き渡しています。
ログ出力では、this がそれぞれ自身のオブジェクトを指し、インスタンスから各プロパティにアクセスすると、それぞれの値が格納されていることが確認できます。
apply について
apply の概要
[code]
method.apply(thisArg[, argsArray])
[/code]
thisArg は call と同様、method の this パラメータとして使われる値。thisArg を null か undefined とすると、グローバルオブジェクト(Window)となる。argsArray は method に渡される引数。
サンプルコード
[code]
function Person() {
// 受け取る配列はオブジェクトなので配列に変換
var args = Array.prototype.slice.apply(arguments, [0, 2]);
this.name = args[0];
this.age = args[1];
return this;
}
function Gender(args) {
Person.apply(this, args); // apply の第2引数は配列
this.sex = args[2];
}
var fArray = [‘Taro’,45,’male’];
var mArray = [‘Hanako’,35,’female’];
var father = new Gender(fArray);
var mother = new Gender(mArray);
console.log(father.name);
console.log(father.age);
console.log(father.sex);
console.log(mother.name);
console.log(mother.age);
console.log(mother.sex);
[/code]
結果
[code]
Taro
45
male
Hanako
35
female
[/code]
このサンプルコードでは2つの apply を使っています。
まず最初に、father, mother の各プロパティの値を配列 fArray, mArray とし、Gender から Person を apply で呼び出し、引数を配列 args で引き渡しています。
次に、Person 側では受け取った配列がオブジェクトなので、arguments オブジェクトから apply で Array のメソッドを呼び出し配列として扱えるようにしています。
ログ出力では call のときと同じように、各プロパティの値が出力されていることが確認できます。
まとめ
call や apply を使用すれば、あらゆる場所から、オブジェクト内に定義されたメンバ関数を使用することが出来るようになってしまいます。
この辺が JavaScript が柔軟であり、混乱する理由のひとつといえるかと思います。
この記事がみなさんのお役に立ちましたら、下記「Share it」よりブックマークやSNSで共有していただければ幸いです。