JS初心者が call , apply, bind, this の関連を考える

  • call, apply は使い方がいまいちわからないメソッドの筆頭格でした。
  • これを書いてみても、使いみちがよくわからない筆頭格の座を譲ることはありません(笑)
  • しかし、この仕組みを理解することで、JSが少しわかったような気がします.
  • まずは、簡単に使ってみます。 セミコロンの省略を嫌がる人がいることは知っていますが、必須なとき以外は、省略させていただきます。
const hana = { name: '華'}
const tomo = { name: '友'}

const sayFunc = function() {
    return `Hello ${ this.name }`
}

console.log(sayFunc.call(hana))
console.log(sayFunc.call(tomo))
Hello 華
Hello 友
  • sayFunc関数のthis の中に、hanaオブジェクト、tomoオブジェクトが入る感じでしょうか
const sayFunc = function() {
    return `Hello ${ hana.name }`
}
  • このsampleはあまり役に立たないので、hanaオブジェクト、tomoオブジェクトに追加してみます。
const hana = { name: '華'}
const tomo = { name: '友'}

const addFunc = function(age, height) {
    this.age = age
    this.height = height
}

addFunc.call(hana, 23, 162)
addFunc.call(tomo, 33, 183)

console.log('hana: ', hana)
console.log('tomo: ', tomo)
hana:  { name: '華', age: 23, height: 162 }
tomo:  { name: '友', age: 33, height: 183 }
  • それぞれのオブジェクトに追加されているのがわかります。 thisがそれぞれのObjectを指しているんですね。
  • これで、callメソッドがオブジェクトの追加に使えることがわかります。
  • apply はどうでしょうか、これは配列要素を処理するときに、callの代わりに使われます。
const hana = { name: '華'}
const tomo = { name: '友'}

const addFunc = function(age, height) {
    this.age = age
    this.height = height
}

addFunc.apply(hana, [23, 162])
addFunc.apply(tomo, [33, 183])

// addFunc.call(hana, 23, 162)
// addFunc.call(tomo, 33, 183)

console.log('hana: ', hana)
console.log('tomo: ', tomo)
  • 代入演算子、スプレッド演算子、などを使ってもう少しスマートにしてみます。
const hana = { name: '華'}
const tomo = { name: '友'}

const addFunc = function({ age, height }) { // call用
    Object.assign( this, { age, height })
}
const addFunc2 = function( age, height ) { // apply用
    Object.assign(this, { age, height })
}

const hanaData = {
    age: 23,
    height: 162
}
const tomoData = [33, 183]


addFunc.call(hana, { ...hanaData })
addFunc2.apply(tomo, tomoData )

console.log('hana: ', hana)
console.log('tomo: ', tomo)
  • 引数に生データを入れない分も、汎用性が上がったかと思います。
  • ここで、thisを縛るメソッドに bind がありますので、使ってみます。
const hana = { name: '華'}
const tomo = { name: '友'}

const addFunc = function({ age, height }) { // call用
    Object.assign( this, { age, height })
}
const addFunc2 = function( age, height ) { // apply用
    Object.assign(this, { age, height })
}

const addBindHana = addFunc.bind(hana)
const addBindTomo = addFunc2.bind(tomo)

const hanaData = {
    age: 23,
    height: 162
}
const tomoData = [33, 183]


addBindHana({ ...hanaData })
addBindTomo(...tomoData )
// addFunc.call(hana, { ...hanaData })
// addFunc2.apply(tomo, tomoData )

console.log('hana: ', hana)
console.log('tomo: : ', tomo)
  • bindすれば、callもapplyも必要無くなることがわかります。

  • ちなみに、今回のようなオブジェクトの追加は、もっと簡単な実装があるかと思います。

const hana = { name: '華'}

const hanaData = {
    age: 23,
    height: 162
}

Object.assign( hana , { ...hanaData })
console.log('hana: ', hana)
  • 別オブジェクトにする場合
const hana = { name: '華'}

const hanaData = {
    age: 23,
    height: 162
}

const hanaAdd = {...hana, ...hanaData}

console.log('hanaAdd: ', hanaAdd)
  • 今回自分で、call applyを使ってみて、このメソッドはあまり使わないなと感じたのですが、これを使うことで、ややこしいthisの事が、少し整理できたように思います。