関数型プログラミング
//CODE


テスト
ホゲホゲ

//新しい関数を返す関数の例

//Oreily p125
  function isa(type, action) {
    return function(obj) {
      if(type === obj.type) return action(obj);
    }
  }

//これをswicthの代わりに使う
 var hogehoge = dispatch(
 isa('apple', function(obj){ return func1(obj.msg);}),
 isa('orange', function(obj){ return func2(obj.target);}),
 function(obj){ funcdefo(obj.type);};
 );

//カーリー化
function add(x) {
    return function(y) {
        return x + y;
    };
}

//以下のように使う
var add3 = add(3)
add3(y)

//つまり継承してる?

//dispatch
//ディスパッチとは、発送(する)、派遣(する)などの意味を持つ英単語で、ITの分野では同種の複数の対象から一つを選び出したり、データの送信、資源の割り当て、機能の呼び出しなどを表すことが多い。

function dispatch() {
// 引数 = 連想配列から値のみの配列を作る:であってる? let funs = Object.values(arguments);
// 違うね。。。 ...argumentsでよくね??
  let funs = _.toArray(arguments);
  let size = funs.length;

  return function (target) {
    let ret = undefined;

//引数 = 連想配列 の最初を除外した配列を返す
//dispatch(type,..arg)じゃだめなの??
    let args = _.rest(arguments);

    for (let funIndex = 0; funIndex < size; funIndex++) {
      let fun = funs[funIndex];
      ret = fun.apply(fun, construct(target, args));
      if (existy(ret)) return ret;
    }

    return ret;
  };
}


Object.createで継承

//Object.createで継承
const person = {
  isHuman: false,
  printIntroduction: function() {
    console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
  }
};

const me = Object.create(person);

me.name = 'Matthew'; // "name" is a property set on "me", but not on "person"
me.isHuman = true; // inherited properties can be overwritten

me.printIntroduction();
// expected output: "My name is Matthew. Am I human? true"

//es6:オブジェクトのメソッド記法
const obj = {
    method() {
        console.log(this);
    }
}

//
var Animal = {
  create(type){
    var animal = Object.create(Animal.prototype);
    animal.type = type;
    return animal;
  },
  isAnimal(obj, type){
    if(!Animal.prototype.isPrototypeOf(obj)){
      return false;
    }
    return type ? obj.type === type : true;
  },
  prototype: {}
};

//Object.prototype.isPrototypeOf()
//オブジェクトが別のオブジェクトのプロトタイプチェーンに存在するかどうかを判定します。

//Object.assign
//すべての列挙可能な自身のプロパティの値を、
//1 つ以上のコピー元オブジェクトからコピー先オブジェクトにコピーするために使用されます。
//変更されたコピー先オブジェクトを返します。

const target = { a: 1, b: 2, c:1 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }

console.log(source);
// expected output: Object { b: 4, c: 5 }


var Dog = {
  create(name, breed){
    var dog = Object.create(Dog.prototype);
    Object.assign(dog, Animal.create("dog"));
    dog.name = name;
    dog.breed = breed;
    return dog;
  },
  isDog(obj){
    return Animal.isAnimal(obj, "dog");
  },
  prototype: {
    bark(){
      console.log("ruff, ruff");
    },
    print(){
      console.log("The dog " + this.name + " is a " + this.breed);
    }
  }
};

Object.setPrototypeOf(Dog.prototype, Animal.prototype);

//Object.setPrototypeOf
//指定されたオブジェクトのプロトタイプ (つまり、内部の [[Prototype]] プロパティ) を、
//別のオブジェクトまたは null に設定します。

var sparkie = Dog.create("Sparkie", "Border Collie");
sparkie.name;    // "Sparkie"
sparkie.breed;   // "Border Collie"
sparkie.bark();  // console: "ruff, ruff"
sparkie.print(); // console: "The dog Sparkie is a Border Collie"
Dog.isDog(sparkie); // true


apllyとcall

//第一引数は、いっしょ
関数名.apply(関数の処理の対象となる要素,関数で使う引数(配列のみ) );
関数名.call(関数の処理の対象となる要素,関数で使う引数,関数で使う引数,関数で使う引数… );

function a(){
  console.log(this); // 結果: undefined
  console.log(this.message); // 結果: TypeError: this is undefined
}
a.call( { message: "test!!" } );
      //   ↑thisとして渡すオブジェクト
      // 実行結果 : ①  this : object { message: "test!!" }
      //            ②  this.message :  "test!!"

a.apply( { message: "test!! test!!" } )
      //   ↑thisとして渡すオブジェクト
      // 実行結果 : ①  this :  object { message: "test!! test!!" }
      //            ②  this.message : "test!! test!!"


var edward = {
    name: 'エドワード・エルリック',
    age: 16,
    job: '国家錬金術師',
    presentation: function(feeling, dayTimeZone) {
        if (feeling === 'normal') {
            console.log('Good ' + dayTimeZone + '! 私は' +  this.name + '。' + this.age + '歳です。アメストリス国の' + this.job + 'です。');
        } else if (feeling === 'angry') {
            console.log('はぁ? ' +  this.name + 'の名を知らないって?アメストリス国で' + this.age + '歳の天才' + this.job + 'と言ったら私だ。よく覚えとけ。Good ' + dayTimeZone + '! じゃあな!');
        }
    }
};

var winry = {
    name: 'ウインリィ・ロックベル',
    age: 15,
    job: '機械鎧技師'
};

edward.presentation.call(winry, 'angry', 'night');

edward.presentation.apply(winry, ['normal', 'afternoon']);

arguments引数を配列にとる:残余引数演算子

//Oreily p125

function avg() {
  var sum = 0;
  for (var i = 0, j = arguments.length; i < j; i++) {
    sum += arguments[i];
  }
  return sum / arguments.length;
}

avg(2, 3, 4, 5); // 3.5

//残余引数演算子
function avg(...args) {
  var sum = 0;
  for (let value of args) {
    sum += value;
  }
  return sum / args.length;
}

avg(2, 3, 4, 5); // 3.5