JavaScriptのthisやあれこれ

## はじめに
初学者です。
基本は備忘録

## 関数とthis
```js
function fn(a, b) {
  console.log(a, b);
}

fn(1) //結果: 1 undefined
fn(null, 1)//結果 null 1
//2つめだけ使いたい場nullを使う
```
*jsでは同じ関数が2つ以上ある場合後に書いた方が実行される*
*関数式で宣言するとエラーで教えてくれる*

```js
function fn(a, b = 2) { //デフォルト値を設定できる
  console.log(a, b);
}
fn(1, null)// 1 null
fn(1, undefined)// 1 2
//意図的に空にしたい場合はnullにする。undefinedは基本使わない
```

### argumentsとは
```js
function fn(a, b) {
  console.log(a, b);
}

fn(1, 2)
```
*argumentsとは実引数のことである*
*上記のコードだと1と2が該当する*

## 関数とオブジェクト
**関数**は**実行可能なオブジェクト**である
*実行可能な点以外は全て一緒*

## コールバック関数
*他の関数の引数として渡された関数のこと*

```js
function hello(name) {
  console.log('hello' + name)
}

function fn(cd) {
  cb('Ren')
}

fn(hello)//結果: hello Ren
//実引数(上記だとhello)がコールバック関数
```
*コールバック関数は無名関数を使って直接記述しても使用可能*

```js
function greet() {
  console.log('Hello')
}

setTimeout(greet, 2000)//2秒後にHelloと表示
//greetがコールバック関数
```
*なぜコールバック関数が存在するのか？*
上記のコードは「○秒後に実行」＋「helloと表示」の2つの関数で成り立っている
関数helloを別なものに変更するだけで変更した関数も○秒後に発動できる
処理を切り分けることでコードの**再利用性**が高まっている

## thisについて
thisは**呼び出し元のオブジェクト**への参照を保持する
実行コンテキストによってthisの参照先は変わる

```js
const person = {
  name: 'Ren',
  hello: function() {
    console.log('Hello' + this.name)
  }
}
person.hello() //結果 Hello Ren
//thisは呼び出し元のpersonを参照している
```

## 参照のコピーとthis

```js
window.name = 'Miku'

const person = {
  name: 'Ren',
  hello: function() {
    console.log('Hello' + this.name)
  }
}
const ref = person.hello
ref(); //Hello Miku
//refにはhello()の参照先の関数が渡されるのでオブジェクトを経由しない。　
//thisはレキシカルスコープのwindowを参照する
```

*以下のように考えることができる*
**オブジェクトのメソット**として実行される場合
'this' => 呼び出し元のオブジェクト

**関数**として実行される場合
'this' => グローバルオブジェクト

### コールバック関数とthis

```js
window.name = 'Miku'

const preson = {
  name: 'Ren',
  hello: function() {
    console.log('Hello', this.name)
  }
}

function fn(ref) {
  ref();
}

fn(person.hello)//Hello Miku
//refにはメソットの参照先の関数が直接入る(関数への直接の参照)
//オブジェクトは経由しないため、thisにはwindowオブジェクトが格納される
//レキシカルスコープはfnだが関数として実行されているためwindowオブジェクトを参照
```
*メソットを他の変数に代入すると、オブジェクト経由で呼び出すのではなく関数を格納している変数から直接呼ぶため、呼び出し元のオブジェクトは基本的にwindowオブジェクトになる*

## bindとthis
*bindを使うことでthisや引数を固定することができる*
**bindによるthisの束縛と呼ぶ**
*bindで固定する場合元の関数とは別の関数が新しく作成される*

```js
const preson = {
  name: 'Ren',
  hello: function() {
    console.log('Hello', this.name)
  }
}

const helloRen = person.hello.bind(person);
//person.helloのthisの参照を固定できる

function fn(ref) {
  ref();
}

fn(helloRen)//結果 Hello Ren;

---------------------------------------------------------
function a() {
  console.log('hello' + this.name);
}

const b = a.bind({name: 'Ren'});
b()//結果 hello Ren
```

*引数を固定*

```js
function a(name) {
  console.log('Hello' + name);
}

const b = a.bind(null, 'Ren')
//第一引数はthis,第二引数は引数を固定する
//thisを必要としない場合nullにする

b()//結果: Hello Ren
```

## applyとcall
*bindとの違いは定義と同時に実行までされる点*

```js
function a(name, name1) {
  console.log('Hello ' + name + ' ' + name1);
}

const tim = {name: 'Tim'};

a.apply(tim, ['Ren', 'Miku']);//第一引数はthis,第二引数は(配列)を固定する
a.call(tim, 'Ren', 'Miku');//第一引数はthis,第二引数は引数を固定する
//applyとcallは定義するのと同時に実行まで行われる
```

## アロー関数とは
*無名関数を記述しやすくした省略記法*

```js
const b = (name) => {
  return 'hello' + name;
}

//引数が1つなら()は省略できる
//実行行が1行なら{}とreturnは省略できる

const b = name => 'hello' + name;

console.log(b('Ren'))//結果: hello Ren
```
*無名関数とアロー関数の挙動には違いがある*

-|無名関数|アロー関数
-|-|-
this|○|x
arguments|○|x
new|○|x
prototype|○|x

### アロー関数とthis
*アロー関数はthisを保持しないためレキシカルスコープに探しに行く*
*アロー関数はthiwを保持しないのでbind等で束縛もできない*

```js
const person = {
  name: 'Ren';
  hello: function() {
    console.log('Hello' + this.name)//Hello Ren
    //無名関数はthisを保持するためオブジェクトへの参照を保持
  }
}
```
```js
window.name = 'Miku';
const person = {
  name: 'Ren';
  hello: () => {
    console.log('Hello' + this.name)// Hello Miku
    //アロー関数はthisを保持しないためレキシカルスコープ参照
    //このコードだとwindowオブジェクトがレキシカルスコープ
  }
}
```
```js
window.name = 'Miku';
const person = {
  name: 'Ren';
  hello() {
    console.log('Hello' + this.name)// Hello Ren
    const a = ()  => console.log('Bye' + this.name)
    a();// Hello Ren
  }
}
//アロー関数はthisを保持しないためレキシカルスコープを参照
//このコードだと関数helloの関数スコープがレキシカルスコープ
//関数helloはメソットとして実行しているのでthisを保持している
```