Programming Self-Study Notebook

勉強したことを忘れないように! 思い出せるように!!

JavaScriptの文法(関数)

f:id:overworker:20200406080809j:plain:h250

戻り値

  • 関数の値はreturnを使って呼び出し元に戻します。
    • 関数からreturnで戻らない場合や値が指定されないreturnで戻る場合、関数が戻す値はundefinedとなる。
    • 関数は任意の型を返すことができる。

呼び出しと参照

  • JavaScriptで関数はオブジェクトです。
    • 関数を関数の引数として渡すことができる。
    • 関数を変数に代入することができる。
種類 記述方法 詳細
呼び出し 関数名に()をつける 関数の本体が実行される
参照 関数名のみ 実行されない
function getGreeting() {
  return "Hello World!";
}
//呼び出し
console.log(getGreeting()); // "Hello World!"

//参照
console.log(getGreeting);
/*
ƒ getGreeting() {
  return "Hello World!";
}
*/

// 関数を変数に代入する(関数の名前を変更する)
const f = getGreeting;
console.log(f());    // "Hello World!"

// 関数をオブジェクトのプロパティに代入する
const o = {};
o.f = getGreeting;
console.log(o.f());    // "Hello World!"

// 配列の要素として関数を代入する
const arr = [1,2,3];
arr[1] = getGreeting;
console.log(arr[1]());    // "Hello World!"

関数の引数

  • 仮引数がプリミティブ型の変数の場合、仮引数に対し関数内で変更を加えても呼び出し元の値には変化が起こらない。
function f(x){
    console.log(`関数内1:${x}`);
    x = 5;
    console.log(`関数内2:${x}`);
}

const x =10;
console.log(`関数外1:${x}`);
f(x);
console.log(`関数外2:${x}`);
/*
// 表示内容
関数外1:10
関数内1:10
関数内2:5
関数外2:10
*/
  • 仮引数がオブジェクト型の変数の場合、関数内部で別オブジェクトを参照する記述を実行するまでは元のオブジェクトを参照する。
    • 仮引数で受け取ったオブジェクトの既存キーの値を変更する:呼び出し元と同一のオブジェクトを参照
    • 仮引数で受け取ったオブジェクトにキーを追加:別の新しいオブジェクトを参照
function f1(o){
console.log(`    f1-1:${o.message}`);
o.message = "f1内で書き換え";
console.log(`    f1-2:${o.message}`);
}

function f2(o){
  console.log(`    f2-1:${o.message}`);
  o ={
    message:"f2内で同名オブジェクト追加",
  };
  console.log(`    f2-2:${o.message}`);
}

function f3(o){
  console.log(`    f3-1:${o.message}`);
  o.message = "f3内で別名オブジェクト追加";
  o.message2 = "f3内で別名オブジェクト追加";
  console.log(`    f3-2:${o.message}`);
}

function f4(o){
  console.log(`    f4-1:${o.message}`);
  o.message = "f4内で別名オブジェクト削除";
  delete o.message2;
  console.log(`    f4-2:${o.message}`);
}
let o ={
  message:"初期値",
};
console.log(`呼び出し元1:${o.message}`);
f1(o);
console.log(`呼び出し元2:${o.message}`);
f2(o);
console.log(`呼び出し元3:${o.message}`);
f3(o);
console.log(`呼び出し元4:${o.message}`);
f4(o);
console.log(`呼び出し元5:${o.message}`);

/*
呼び出し元1:初期値
    f1-1:初期値
    f1-2:f1内で書き換え
呼び出し元2:f1内で書き換え
    f2-1:f1内で書き換え
    f2-2:f2内で同名オブジェクト追加
呼び出し元3:f1内で書き換え
    f3-1:f1内で書き換え
    f3-2:f3内で別名オブジェクト追加
呼び出し元4:f3内で別名オブジェクト追加
    f4-1:f3内で別名オブジェクト追加
    f4-2:f4内で別名オブジェクト削除
呼び出し元5:f4内で別名オブジェクト削除
*/

引数と関数

  • JavaScriptでは、関数は名称のみで区別される(引数の数によらない)
    • すべての関数は任意個の引数を指定して呼び出すことができる。
    • 引数へ値をセットする際に分割代入が可能
    • 呼び出し側で関数定義側が用意している引数が指定されなかった場合、undefinedが指定されたものとして扱われる。
  • 関数定義側は呼び出し側で引数がセットされなかった時のためのデフォルト引数を要しすることができる。
function f(a,b="default",c=3){
  return `${a} - ${b} - ${c}`;
}
let o ={
  message:"初期値",
};
console.log(f(5,6,7)); // 5 - 6 - 7
console.log(f(5,6));   // 5 - 6 - 3
console.log(f(5));     // 5 - default - 3
console.log(f());      // undefined - default - 3

オブジェクトのメソッド

  • オブジェクトのプロパティとして指定される関数のことをメソッドという。
const o  = {
  name: "Takeshi", 
  message: function(){return "Hello!";},
}
console.log(o.name);       // Takeshi
console.log(o.message());  // Hello!

// 上記を省略記法(ショートハンド)で表現する
const o2  = {
  name: "Takeshi", 
  message(){return "Hello!";},
}
console.log(o2.name);       // Takeshi
console.log(o2.message());  // Hello!

this

  • 「オブジェクト」と「オブジェクトのプロパティである関数(メソッド)」を束縛する。
const o  = {
  name: "Takeshi", 
  message(){return `Hello! My name is ${this.name}`;},
}
const message = o.message;
console.log(message === o.message); // true
console.log(o.message());           // "Hello! My name is Takashi"
console.log(message);               // ƒ message(){return `Hello! My name is ${this.name}`;}

関数式と無名関数

  • 関数式とは関数宣言に対し、関数名を省略する記法のコト
    • 関数式は値をとして関数を返す
      • 関数式変数などに代入することが可能
      • 関数式はすぐに呼び出すことも可能
  • 関数式関数宣言の違いは実質的にはない
    • 周囲の文脈を把握する必要がある
const f = function(){
    // ...
}

アロー演算子

  • 無名関数の一種
  • 無名関数を引数に渡す場合によく利用される

特徴

  • functionという単語を省略できる。
  • 引数が一つならば()を省略できる。
  • 関数本体が一つの式となる場合、{}、それにreturnを省略できる。

通常の関数とは異なる点

  • thisが他の変数と同様に、語彙的に束縛される
  • オブジェクトのコンストラクタとして使えない
  • argumentsが使えない
const f1_1 = function(){ return "Hello!";}
const f1_2 = () => "Hello!";
console.log(f1_1());   // Hello!
console.log(f1_2());   // Hello!

const f2_1 = function(name){ return `My name id ${name}`;}
const f2_2 = name => `My name id ${name}`;
console.log(f2_1("Takeshi"));   // My name id Takeshi
console.log(f2_2("Takeshi"));   // My name id Takeshi

const f3_1 = function(a,b){ return a + b;}
const f3_2 = (a,b) => a+b;
console.log(f3_1(3,5));   // 8
console.log(f3_2(3,5));   // 8

call、apply、bind

call

  • すべての関数に対して利用できるメソッド
  • thisを特定の値に指定したうえで、関数を呼び出す
  • callの第一引数にはthisを束縛したい値を指定する
    • 残りの引数には呼び出す関数の引数を入れる
const taro = {name :"Taro"};
const hanako = {name :"Hanako"};

// 通常はthisは使用できない
function greet(){
    return `My name is ${this.name}`;
}
console.log(greet.call(taro));     // My name is Taro
console.log(greet.call(hanako));   // My name is Hanako
console.log(greet());              // error

apply

  • 引数を配列として受け取る(callは引数を直接受け取る)
    • 既に、関数が用意されていて、その値を関数の引数として使いたい場合
const arr = [2,3,-5,15,7];
console.log(Math.min.apply(null,arr)); // -5
console.log(Math.max.apply(null,arr)) // 15;

// スプレッド演算子を利用した場合
console.log(Math.min.apply(...arr)); // -5
console.log(Math.max.apply(...arr)) // 15;
  • 以下のapplyはスプレッド演算子を使用してcallに置き換えることが可能
const taro = {name :"Taro"};
const taro2 = {name :"Taro"};
const arr = [2004,"student"];
function update(birthyear,occupation){
  this.birthyear = birthyear;
  this.occupation = occupation;
};

// applyの場合
update.apply(taro,arr);
console.log(taro);  // {name: "Taro", birthyear: 2004, occupation: "Student"}

update.call(taro2,...arr);
console.log(taro2); // {name: "Taro", birthyear: 2004, occupation: "Student"}

bind

  • thisの値をある関数と永続的に結びつけることができる。
    • 一度bindでセットされた値は、callapply別のbindとも結びつく

参考文献