このブログのコンセプトって○○なん、知ってた? 何それ気になる〜

【コーディング週間日報】5/2(日)〜 5/8(土)の学習

たーやま

5/2(日)〜 5/8(土)に行ったことを記載しました。

目次

5/3(月)のアウトプット

Udemy で学習している JavaScript についてまとめました。

関数

引数が二つあったとき、b に値を入れたいとします。

しかし、( ) 内に一つしか数字を入れなかった場合は、a に渡ってしまいます

function fn(a, b) {
    console.log(a, b);
}

fn(1); // a = 1, b = undefined

こういう場合は、fn(null, 1) などに設定しましょう。

また JavaScript では、関数名が重複していた場合は、後から宣言された方の関数が実行されます。

この場合、エラーが起きないことは注意すべき点です。

引数の数を変えたとしても、異なる関数にはならず同じものとして扱われます。

function fn(a, b) {
    console.log(a, b);
}

function fn(a) {
    console.log(392);
}

fn(1);

// 392が実行される

もし関数の重複を避けたい場合は、const を使いましょう。

const fn = function fn(a, b) {
    console.log(a, b);
}

function fn(a, b) {
    console.log(392);
}

fn(1);

// エラーが発生する

また、値が渡ってこなかったときのためにデフォルト値を設定することもできます。

function fn(a, b=1) {
    console.log(a, b);
}

fn(1);

// a = 1, b = 1

ちなみに、null とundefined で挙動が変わります。

function fn(a, b=1) {
    console.log(a, b);
}

fn(1, null);

// a = 1, b = null
function fn(a, b=1) {
    console.log(a, b);
}

fn(1, null);

// a = 1, b = null

function fn(a, b=1) {
    console.log(a, b);
}

fn(1, undefined);

// a = 1, b = 1

undefined の場合は、デフォルト値が返ってきます。

・関数とオブジェクト

関数:実行可能なオブジェクトのこと。

 function a() {
    console.log('hello');
}

a.prop = 1;
a.thing = function () {
    console.log('thing');
}

a(); // hello
a.thing(); // thing
console.log(a.prop); // 1

宣言した関数に対して、ドット「.」でプロパティやメソッドを登録できるので、関数 a はオブジェクトであると言えます。

()は「実行する」という意味になることも非常に重要なので覚えておきましょう。

コールバック関数

関数は実行可能なオブジェクトであることは先ほど説明しました。

JavaScript では、他の関数に引数として渡される関数(=コールバック関数)を定義できます。

function world() {
    console.log('hello world');
}

function fn(cb) {
    cb();
}

fn(world); // hello world

引数 cb が function fn 内で実行されるようします。

fn の ( ) 内に world を渡すと hello world が実行されます。これがコールバック関数です。

関数はオブジェクトとしても扱えますので、関数を引数として渡すこともできます。

では、コールバック関数の中に引数があった場合はどうなるのか…。

function world(name) {
    console.log('hello world ' + name);
}

function fn(cb) {
    cb('Taro'); // ← ココ
}

fn(world); // hello world Taro

fn(function (name) {
    console.log('hello ' + name);
}); // hello Taro

cb の () 内に文字列 Taro を入れてみました。

cb が実行された時に、引数として Taro が渡ってきます。

fn 内で world を渡していますよね。

なので、function world の () 内には Taro の文字列が渡ってくるようになります。

function world の () 内に name という変数を定義することで、実行結果が返ってきます。

this

呼び出し元のオブジェクトへの参照を保持するキーワード。

超わかりやすく言うと、ドット「.」の前についているオブジェクトが this です。

const person = {
    name: 'Tom',
    hello: function () {
        console.log('Hello ' + this.name);
    }
}

person.hello(); // Hello Tom

ドット「.」の前についているのは person です。なので、this はperson への参照を保持しています。

ちなみに this は person に置き換えても、Hello Tom と表示されます。

console.log からみたら、オブジェクトの外側にある変数(person)は、レキシカルスコープです。

変数の参照ができるため、実行が問題なく完了します。

こんな感じで、person.hello(); として呼び出された場合、hello(); で実行される this は、呼び出し元の person を参照します。

function hello() {
    console.log(this);
}

hello(); // window オブジェクトが返ってくる

この場合は、どこにもドットがありません。

なので、グローバルオブジェクトである window オブジェクトが返ってきます

5/4(火)のアウトプット

参照のコピーとthis

覚え方として、ドット「.」の前についているオブジェクトが this だと説明しました。

しかし、person.hello(); を他の変数にコピーすると、挙動が変わります。

window.name = 'Ken';

const person = {
    name: 'Tom',
    hello: function () {
        console.log('Hello ' + this.name);
    }
}

const bye = person.hello;
bye(); // Hello Ken

この場合イメージとしては、person.hello を ref に コピーすると、hello が参照している function もコピーされます

そして ref は hello が参照している function を参照しません。

コピーされた function を参照します。

そして ref は、person を経由せず、直接コピーされた function  を参照。

呼び出し元は person ではないため、グローバルオブジェクトを参照します。

なので、window メソッドで定義した「Ken」が表示されました。

たーやま

実行元にドット『.』がなかったら、グローバルオブジェクトを参照する感じやな。

コールバック関数と this

person.hello をコールバック関数として他の引数に与えた場合はどうなるでしょうか?

window.name = 'Ken';

const person = {
    name: 'Tom',
    hello: function () {
        console.log('Hello ' + this.name);
    }
}

person.hello();
function fn(ref) { // … 1)
 ref();
}

fn(person.hello); // Hello Ken

この場合も同様に、メソッドを他の変数に代入しているのと同じです。

1)で渡されてくるコールバック関数は、person.hello が参照している先の関数が ref に渡されます。

なので関数を実行するのと同じになるため、グローバルオブジェクトである window メソッドを参照しています。

bind と this

this の挙動を変えるためには、bind を使うと良いです。

window.name = 'John';

const person = {
    name: 'Tom',
    hello: function() {
        console.log('Hello ' + this.name);
    }
}
person.hello();

const bth = person.hello.bind(person);

function fn(ref) {
    ref();
}

fn(bth); // hello Tom

bind の引数で渡した値(person)を、hello の中で実行される this の参照先として設定。

設定した関数を新しい関数 bth に返却しています。

関数 bth を実行したら、bind で指定した オブジェクトが this の参照先となるため、コールバック関数を使っても hello Tom が呼び出されます。

5/5(水)のアウトプット

call, apply と this

bind:this や引数の参照先を変更します。使用時に実行まではしません
call, apply:this や引数の参照先を変更します。使用時に関数の実行もします

では、bind からみてみましょう。

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

const b = a.bind({ name: 'Teru' });

b(); // hello Teru

変数 b で a にある this を bind によって束縛しています。なので、b を実行すると hello Teru が出力されます。

これを apply, call を使って表示させてみます。

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

const teru = { name: 'Teru' };

const b = a.bind(teru);

b(); // hello Teru

a.apply(teru); // hello Teru
a.call(teru); // hello Teru

bind を使用した場合は、実行する必要があります。

しかし、apply や call の場合は、実行までされるため、実行の処理は記述する必要がありません。

call と apply の違いって何?

って思われるかもしれませんね。

違いはこんな感じです。

call:第二引数以降を順番に引数として渡す
apply:第二引数に配列として渡す。

例を使ってみます。

function a(name, name1) {
    console.log('hello ' + name + ' ' + name1);
}

const teru = { name: 'Teru' };

a.apply(teru, ['Mild_seven', 'Wakaba']);  // hello Mild_seven Wakaba
a.call(teru, 'Winston', 'Seven_star'); // hello Winston Seven_star

a の仮引数を2つ用意し、apply では配列を、call では仮引数の値を設定しました。

call は bind と似ていますが、実行までされる点が異なっています

apply は 配列に渡された値が展開され、a の仮引数に順番に渡っていきます。

たーやま

どうでもいいですが、タバコはめっちゃ苦手です。笑

アロー関数

function の定義をシンプルに記述できる方法です。ES6 から導入されました。

function a(name) {
    return 'Hi ' + name;
}

一般的な関数は上記のように記述します。では、アロー関数を使って関数式に直してみましょう。

function a(name) {
    return 'Hi ' + name;
}

const b = (name) => {
    return 'Hi ' + name;
}

console.log(b('Kerry')); // Hi Kerry

「=>」を入れることで、式を省略できました。しかし引数と実行の行が一つの場合、もっと省略できます

const b = name => 'Hi ' + name;
console.log(b('Kerry')); // Hi Kerry

これですっきりとしたコードになりました。

引数を2つ以上とる場合は、引数の ( ) は省略できません。

const b = (name, name1) => 'Hi ' + name +  ' ' + name1;
console.log(b('Kerry', 'Green')); // Hi Kerry Green

また、引数を取らない場合も省略できません。

アロー関数とthis

無名関数とアロー関数では、this の挙動に違いがでてきます。

window.name = 'John';

const person = {
    name: 'Tom',
    hello: function() {
        console.log('Hello ' + this.name);
    }
}

person.hello(); // Hello Tom

この場合の this は、person を参照するため、Hello Tom になります。

では、hello の関数をアロー関数に置き換えてみましょう。

window.name = 'John';

const person = {
    name: 'Tom',
    hello: () => {
        console.log('Hello ' + this.name);
    }
}

person.hello(); // Hello John

person は、グローバルコンテキストに定義されています。

そして、グローバルコンテキストの this の参照先は window オブジェクト。

ここに person.hello を実行すると、アロー関数が呼び出されます。

アロー関数は this を呼び出さないため、スコープチェーンを辿って、外側のレキシカルスコープで探します。

そこで window オブジェクトが見つかるため、John が実行結果として出力されます。

5/6(木)のアウトプット

コンストラクター関数

新しくオブジェクトを作成するための雛形になる関数のこと。new 演算子を用いて実行します。

new 演算子で呼ばれると、オブジェクトが生成されます。

この流れを「インスタンス化」といい、オブジェクトのことは「インスタンス」と呼ばれます。

function Person(name, age) {
    this.name = name;
    this.age = age;
}

const toshi = new Person('Toshi', 21);
const taku = new Person('Taku', 19);
const koike = new Person('Koike', 48);

インスタンス化した際に格納したいプロパティを定義するために、this を使います。

これにより new 演算子でインスタンス化した際に、this に続く name プロパティと age プロパティを持ったオブジェクトが生成されます。

この記事が気に入ったら
いいね または フォローしてね!

よかったらシェアしてね!

この記事を書いた人

大阪出身26歳。宮古島の制作会社に勤めています。
コーディングとデザインにシバかれてます。

生き物や自然が好きやけど、特にクワガタムシが好き。
他、チャリとか釣りとか筋トレとかも好き。

目次
閉じる