[JS] Higher-Order Functions, The call and apply bind Methods


Functions Accepting Callback Functions

const oneWord = function (str) {
  return str.replace(/ /g, '').toLowerCase();
};
//g覚えてろ!select all of the spaces
const upperFirstWord = function (str) {
  const [first, ...others] = str.split(' ');
  return [first.toUpperCase(), ...others].join(' ');
};


const transformer = function (str, fn) {
  console.log(`Original string : ${str}`);
  console.log(`Transformed string: ${fn(str)}`);
  console.log(`Transformed by: ${fn.name}`);
};
// 위 함수는 어떻게 string이 transform 되는지 신경쓰지 않는다. 
//오직 transform 하는 부분만 신경씀. 
//관련 code를 다른 함수들로 abstract함. 
//=> created a new level of abstraction

transformer('JavaScript is the best!', upperFirstWord);
//Original string : JavaScript is the best!
//Transformed string: JAVASCRIPT is the best!
//Transformed by: upperFirstWord
transformer('JavaScript is the best!', oneWord);
//Original string : JavaScript is the best!
//Transformed string: javascriptisthebest!
//Transformed by: oneWord
上のtransformer関数はHigher-order関数です.why? this function operates at a higher level of abstraction leaving the low level details to this low level functions.
oneWord, upperFirstWord => lover-level functions with lower level abstraction
const high5 = function () {
  console.log('✋🏻');
};
document.body.addEventListener('click', high5);
// addEventListener : higher-order function, high5 : callback function

['Jonas', 'Martha', 'Adam'].forEach(high5); //✋🏻가 세번 출력된다.
とても重要です)Jsuses all time why callback?makes it easy to split up or code into more reusable and interconnected parts, allows us to create abstraction.
  • abstract : we hide the detail of some code implementation because we don't really care about all that detail.
    消去)抽象(抽象):オブジェクトを表すには、プログラムで必要な要素のみを使用します.内部実装は複雑であるが,実際に露出している部分は簡単な概念である.プログラミングは抽象化の継続である.目的を明らかに!不要なものを隠せ!コアのみ展示!
  • Functions Returning Functions

    const greet = function (greeting) {
      return function (name) {
        console.log(`${greeting} ${name}`);
      };
    };
    
    const greeterHey = greet('Hey');
    greeterHey('Jonas'); //Hey Jonas
    greeterHey('Steven'); //Hey Steven
    
    greet('Hello')('Jonas'); //Hello Jonas
    
    //Arrow function
    const greetArr = greeting => name => console.log(`${greeting} ${name}`);
    
    greetArr('Hi')('Jonas'); //Hi Jonas

    The call and apply Methods

    const lufthansa = {
      airline: 'Lufthansa',
      iataCode: 'LH',
      bookings: [],
      book(flightNum, name) {
        console.log(
          `${name} booked a seat on ${this.airline} flight ${this.iataCode}${flightNum}`
        );
        this.bookings.push({ flight: `${this.iataCode} ${flightNum}`, name });
      },
    };
    
    lufthansa.book(239, 'Jonas Schmedtmann'); //Jonas Schmedtmann booked a seat on Lufthansa flight LH239
    lufthansa.book(635, 'John Smith'); //John Smith booked a seat on Lufthansa flight LH635
    console.log(lufthansa);
    // this = lufthansa
    
    const eurowings = {
      airline: 'Eurowings',
      iataCode: 'EW',
      bookings: [],
    };
    
    const book = lufthansa.book; // 이와 같은 표기 갸능함 why? JavaScript는 first class function 가지고 있으므로!
    
    //book(23, 'Sarah Williams'); // error why? 이 함수는 a regular function call. 
    // In a regular function call, the this keywords points to undefined! (strict mode에서)
    

    Call method


    呼び出しは関数のメソッドです
    最初のパラメータeurowingsを呼び出すことでbook関数内のthisを与えます.
    callメソッドは、どのオブジェクトをthisに設定するかを明確に示すことができます.
    book.call(eurowings, 23, 'Sarah Williams'); // Sarah Williams booked a seat on eurowings flight EW23
    
    console.log(eurowings);
    // bookings : [{flight: "EW 23",name: "Sarah Williams"}] 추가됌!
    
    book.call(lufthansa, 239, 'Mary Cooper');
    console.log(lufthansa);
    
    const swiss = {
      airline: 'Swiss Air Lines',
      iataCode: 'LX',
      bookings: [],
    };
    
    book.call(swiss, 583, 'MaryCooper');
    console.log(swiss);
    

    Apply method


    Callがやったことと同じです.callとの違い:パラメータリストは受け入れられません(ex 583,「MaryCooper」)代わりに一連の論点がある.
    現代jsではapplyメソッドは使用されなくなった.
    const flightData = [583, 'George Cooper'];
    book.apply(swiss, flightData);
    console.log(swiss);
    
    book.call(swiss, ...flightData); // Modern JS (apply와 똑같음)

    The bind Method


    bindメソッドでは、関数はすぐに呼び出されません.Instead it returns a new function where this keyword is bind.
    const bookEW = book.bind(eurowings); // book 함수를 부르지 않음. 
    //This will return a new function where this keyword will always be set to Eurowings.
    const bookLH = book.bind(lufthansa);
    const bookLX = book.bind(swiss);
    
    bookEW(23, 'Steven Williams'); //Steven Williams booked a seat on Eurowings flight EW23
    
    const bookEW23 = book.bind(eurowings, 23);
    bookEW23('Jonas Schmedtmann'); //Jonas Schmedtmann booked a seat on Eurowings flight EW23
    bookEW23('Martha Cooper'); // Martha Cooper booked a seat on Eurowings flight EW23
    
    //const bookEW23 = book.bind(eurowings, 23, 'Jonas'); 와 같은 형태도 가능
    上記のように、パラメータのほんの一部が一部のアプリケーションです.
  • partial application ? a part of the arguments of the original function are already applied, so which means, already set.
  • With Event Listeners

    lufthansa.planes = 300;
    lufthansa.buyPlane = function () {
      console.log(this);
      this.planes++;
      console.log(this.planes);
    };
    
    lufthansa.buyPlane(); //this = lufthansa / 301
    
     document.querySelector('.buy').addEventListener('click', lufthansa.buyPlane);
    // 여기서 this는 .buy element를 가리킨다. event listner에서 callback 함수 내의 this는 element 자체를 가리킨다.  this Keyword 매우 동적.

    手動でthisのobjectを指す方法を設定します

    document
      .querySelector('.buy')
      .addEventListener('click', lufthansa.buyPlane.bind(lufthansa));
    // this = lufthansa

    Partial application


    means that we can preset parameters.
    
    const addTax = (rate, value) => value + value * rate;
    console.log(addTax(0.1, 200));
    
    // this가 따로 없기때문에 null이라 적어줌
    const addVAT = addTax.bind(null, 0.23);
    
    console.log(addVAT(100)); //123
    
    const addTaxRate = function (rate) {
      return function (value) {
        return value + value * rate;
      };
    };
    const addVAT2 = addTaxRate(0.23);
    console.log(addVAT2(100)); //123