JavaScript

JavaScript の call( ) メソッドを雑に説明

More than 3 years have passed since last update.

書き方

function.call(thisObj,args...);

説明用にもうひとつ

targetObject.function.call(thisObj,args...);

call( ) メソッドの概要

call( ) は 指定した targetObject の function を thisObj の メソッドであるかのように呼び出すよ。

ちょっと雑目に説明してみる。まずはコーディング形式から

呼ばれたいメソッドを持つオブジェクト.呼びたいメソッド.call(呼び出したいオブジェクト, 呼びたいメソッドに渡す引数);

すっげーわかりにくいからもうちょっと雑にw

あっちのオブジェクト.あっちのメソッド.call(こっちのオブジェクト, あっちのメソッドに渡す引数);

要するに

call( ) は他のオブジェクトが持つメソッドをさぞ自分のメソッドかのように呼び出すメソッド
 

call( ) の挙動を確認

this が指すもの

function func(){ return this; }
func();

// Window {top: Window, window: Window, location: Location, external: Object, chrome: Object…}

グローバルな空間に置かれたメソッドの this は グローバルオブジェクト を参照するのでブラウザで実行した場合は Window を指す。

call( ) を使ってみる

call( ) を引数なしで使ってみるよ

function func(){ return this; }
func.call();

// Window {top: Window, window: Window, location: Location, external: Object, chrome: Object…}

call( ) の第一引数は this とするオブジェクトを指定することができるのだが、null や undefined を指定すると グローバルオブジェクトを this とするよ。もちろんブラウザで実行した場合は Window を指すよ

function func(){ return this; }
func.call(null);

// Window {top: Window, window: Window, location: Location, external: Object, chrome: Object…}

this を書き換えてみる

じゃあ this を指定する部分に、空のオブジェクトでも渡してみよう

function func() {return this;}
func.call({});

// Object {}

this が空のオブジェクトで書き換えられている。ちょっとしつこいかもだけど、この Object にプロパティとか設定してみる

function func() {return this;}
func.call({hoge: 5});

// Object {hoge: 5}

他のクラスのメソッドを呼んでみる 1

たとえば new される予定の関数を定義したとして

var Hoge = function()
{
  this.prop = "Hoge's prop";
};

Hoge.prototype.hogeFunc = function(){return this.prop;};

var Huga = function()
{
  this.prop = "Huga's prop";
};

Huga.prototype.hugaFunc = function(){return this.prop;};

それぞれに prop を返すメソッドを定義。

new して

var myHoge = new Hoge();

call() でそれぞれのメソッドを呼んでみる

Huga.prototype.hugaFunc.call(myHoge);

// Hoge's prop

hugaFunc を呼んでいるのにも関わらず、this は Hoge のオブジェクトに書き換わっているので Hoge's prop が返ってくる。

もうちょっとわかりやすくすると

var Hoge = function(){};
Hoge.prototype.hogeFunc = function(){return this;};

var Huga = function(){};
Huga.prototype.hugaFunc = function(){return this;};

var myHoge = new Hoge();
Huga.prototype.hugaFunc.call(myHoge);

// Hoge {hogeFunc: function}

hugaFunc は通常 Huga を返すのだが、call( ) で this が書き換わっているので return this では Hoge オブジェクトが返ってきているよ

他のクラスのメソッドを呼んでみる 2

ul タグを用意

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
        <li>8</li>
        <li>9</li>
        <li>10</li>
    </ul>   
</body>
</html>

li を getElementsByTagName で取得

var lists = document.getElementsByTagName('li');

このコをconsole.logなどで吐き出しみると、一見配列のように見える

var lists = document.getElementsByTagName('li');
console.log(lists);

// [li, li, li, li, li, li, li, li, li, li, item: function, namedItem: function]

しかし、実際には配列ではなく、lengthを持っている HTMLCollection であって配列用のメソッドは使えない。

var lists = document.getElementsByTagName('li');
console.log(lists.shift());

VM340:3 Uncaught TypeError: lists.shift is not a function(anonymous function)

そこで slice( ) です。slice( )は配列の一部を返すメソッドです。では call( )を使って呼び出してみます

var lists = document.getElementsByTagName('li');
lists = Array.prototype.slice.call(lists,0);

これで lists は Array となり shift() などが呼び出せるようになります。

lists.shift();

// <li>1</li>

継承時の super( ) とか base( ) 的な「基底クラスのコンストラクタ」を呼ぶ

ここでは継承について特に細かく触れませんが、Huga関数で Hoge.call( ) することで実現。

var Hoge = function(txt){
  this.txt = txt;
};
Hoge.prototype.hogeFunc = function(){ return this.txt; };

var Huga = function(txt){
  Hoge.call(this,txt);
};
Huga.prototype = new Hoge();

var myHuga = new Huga("Hello");
myHuga.hogeFunc();

// "Hello"

まとめ

call( )は〇〇です!という説明よりも、実は何がしたいのか?なんの為に使っているのか?というのを読み解く事のほうが重要で、このメソッド自体の形式的な理解はさほど大変ではないよ
 
同じようなメソッドに apply( ) があるけど、call( ) がしっかりと理解できていれば自ずとわかるものなので、まずはしっかり call( ) の動きや利用シーンなどを理解するといいかもです