본문 바로가기
Programming/JavaScript

this, arrow fucntion, template literals, tagged literals, spread operator, rest 파라미터, apply, call, Class, extends

/*
ES6 JS study from codingapple
내용: this, arrow fucntion, template literals, tagged literals, spread operator, rest 파라미터, apply, call, Class, extends
 */


var 오브젝트2 = {
  data : {
    간지함수 : function(){ console.log(this) }
  }
}
오브젝트2.data.간지함수();  // -> 이 this는 오브젝트2.data 호출
 // this: 나를 담고있는 object 호출     -> 기본 object(전역)은 window 또는 global 호출
 

// constructor: object 생성 기계
function 기계() {
    this.이름 = 'Kim' 
}
 // this: 새로 생성된 obejct 

// eventlistenr안의 this = e.currentTarget = 지금 이벤트가 동작하는 HTML 요소
 document.getElementById('버튼').addEventListener('click', function(e){
  console.log(this)
});

// 콜백함수: 함수 안에 들어가는 함수
var 오브젝트 = {
  이름들 : ['김', '이', '박'],
  함수 : function(){
    console.log(this); // this: 날 담은 object인 '오브젝트'
      오브젝트.이름들.forEach(() => {
        console.log(this) // this: => 안의 this는 새로 설정된 것이 아닌 위에서 쓴 것 재사용(default = window)
      });   // 즉 이 this도 '오브첵트' 호출
  }
}

// Arrow function: 입출력 연산이 단순할 때 직관적. this값 재 정의 없이 재사용한다는 특성 유의
// var 함수이름 = a => a + 10;  파라미터 1개면 () 생략, 코드 1줄이면 {}도 생략 가능
var 함수이름 = (a) => { return a + 10 };

// [1,2,3,4].forEach(function(a) { console.log(a) } );   
[1,2,3,4].forEach(a => console.log(a));

// 연습문제 [1]
var 사람 = {
  name: '손흥민',
  sayHi: function() {
  console.log("안녕 나는", this.name);
  }
}
사람.sayHi(); //안녕 나는 손흥민


// 연습문제 [2]: '자료' object 내에 코드 작성 금지
var 자료 = { 
  data : [1,2,3,4,5] 
}
자료.전부더하기 = function(){
  var 합 = 0;
  this.data.forEach(function(a){
    합 = 합 + a;
  });
  console.log(합);
}
//자료.forEach(fcuntion() {})
자료.전부더하기();


//   document.getElementById('버튼').addEventListener('click', function(){
//     setTimeout(()=>{ console.log(this.innerHTML) }, 1000); 
//   });

// Object.freeze(obj이름) : 'obj이름' 내부 값 변경 불가능하도록 하는 것 -> 에러는 'use strict'에서 출력

// backquote, backtick ``로 문자열 정의: '', "" 와 달리 여러 줄에 걸쳐서 작성 가능, 사이에 js문법 ${}로 추가 가능
`
문자열
여러줄
${자료}
작성
가능
`
// 함수에 문자열 붙여서 실행도 가능: tagged literal ; 참고용

function 해체분석기 (문자들, 변수들) {
    console.log(문자들);
    console.log(변수들);
    console.log(문자들[1]); // '입니다' 출력
}

해체분석기`안녕하세요 ${변수} 입니다` // 해체분석기 인자에 자동으로 string과 변수 할당

// 바지와 양말 문자 위치를 바꿔야할 때 필요한 적절한 해체 분석기?
var pants = 20;
var socks = 100;
`바지${pants} 양말${socks}`;

function 해체분석기1 (문자들, 변수1, 변수2) {    // (문자들, ...변수)
    console.log(문자들[1] + 변수1 + 문자들[0] + 변수2);
}
해체분석기1`바지${pants} 양말${socks}`


function 해체분석기2 (문자들, ...변수) {  // 변수 = [20, 100] array로 저장
    if (변수[0] === 0) {
        console.log(문자들[0], `안팔아요`)
    }
}
해체분석기2 `바지${pants} 양말${socks}`

// Spread Operator: ...대상    -> 함수 안에서, object {}, array [] 안에서 사용가능, 단, 함수인자() 안에 쓴건 rest 파라미터
// 무언가 내용물을 빼서 한번에 입력하고 싶을 때, deep copy가 필요할 때 
// (array 대괄호/object 중괄호 제거, string의 경우 문자 하나씩 분리)

// 한번에 함수 입력하기 예제
function 더하기(a,b,c){
   console.log(a + b + c)
}

var 어레이 = [10, 20, 30];
더하기(...어레이);  //Spread Operator를 활용한 요즘방식
더하기.apply(undefined, 어레이);  // Spread Operator가 없었을 때 사용한 옛날방식 ; apply()는 어레이 받음

// apply(): object 내용물 그대로 적용해서 실행하기     call()과 거의 동일

var person = {
    인사 : function(){
      console.log(this.name + '안녕')
    }
}
  
var person2 = {
    name : '손흥민'
}
person.인사(); // undefined 안녕
person.인사.apply(person2); // 손흥민 안녕   
// apply()와 기능은 같지만 유일한 차이점은 '인사'에 인자를 입력할 때에 넣는 방식이 apply는 [ ]안에 하나로, call은 풀어서 여러개 가능
person.인사.call(person2, 1,2)  


// default 파라미터: 연산, 함수, 인자 넣는것까지 확장 가능
// function 임시함수(){
//   return 10 
// }

// function 더하기 (a, b = 2 * a){  // 연산 + 인자 이용한 dafault 가능
//   console.log(a + b)
// }

// function 더하기 (a, b = 임시함수() ){  // 함수로 default 가능
//   console.log(a + b)
// }

// 더하기(3);

// arguments: 내가 함수에 집어넣은 모든 값을 담은 array 인데 이것도 옛날 문법
// function 함수(a,b,c){
//   for (var i = 0; i < arguments.length; i++){
//     console.log(arguments[i])   
//   }
// }
// 함수(2,3,4);  // 이 경우 arguemnts = [2,3,4]



// Rest 파라미터: 입력된 모든 인자들을 담은 array. 단 마지막에 한 번만 쓸 수 있음
function 함수2(a, b, ...파라미터들){
  console.log(파라미터들)
}
함수2(1,2,3,4,5,6,7); // [3,4,5,6,7]


// Reference data type: array, object는 deep copy가 아니라면 같은 주소를 참조할 뿐임(직접 내용을 저장하지 않음. 화살표만 저장)
var 이름1 = { name : '김' };
var 이름2 = 이름1;  // 이름2도 이름1.name 변경값이 반영됨   -> 이름1 == 이름2
이름1.name = '박';

var 이름1 = { name : '김' };
var 이름2 = { name : '김' };   
이름1 == 이름2  // False. 참조 주소가 다르기 떄문


// 파라미터는 함수 내에 새 변수 var로 할당하는 개념과 같다.
var 이름1 = { name : '김' };

function 변경(obj){
  obj = { name : 'park' };
}

변경(이름1); // 이름 1 값 안바뀜


// constructor: object 복사 기계 목적으로 함수를 이용; 함수는 constructor이므로 대문자로 시작(camelCase 아님)
function Student(name = 'kim', age = 15) {
    this.name = name
    this,age = age
    this.sayHi = function(){
    console.log('안녕하세요' + this.name);
  }
}

// 사용법: new로 새로 생성해서 할당
// contructor에서 생성된 object(st1, st2) = instance
var st1 = new Student('kim')
var st2 = new Student('lee')


function Shopping(name, price) {
    this.name = name,
    this.price = price,
    this.tax = function(){
        console.log(this.price * 0.1)
    }
}

// prototype: 이것으로 저장된 변수, 함수는 prototype에만 보관 -> 변경되지않고 고정되는 것들을 object 형태로 저장저장 (보통 함수를 저장)
// constructor 생성시 해당 object constructor에 생김
// Shopping.prototype.tax = 값 (이런식으로 key, value 바로 할당하거나 prototype = {} 안에 바로 작성) 
  

// console.log(Array.prototype); // 각종 sort, map, push, forEach 함수들 나옴

// //자식 object에서 prototype 호출하기
// console.log(st1.__proto__);
// console.log(Object.getPrototypeOf(st1));
// //자식 object의 원형 출력
// console.log(st1.contructor);
// //상위상위상위 prototype 출력하기 (최종 원형은 Object)
// console.log(st1.__proto__.__proto__.__proto__);


// // constructor 안만들고 obj에 프로토타입 주입하기
// var obj = {}
// var proto = {
//   sayHi() {
//     console.log("안녕")
//   }
// }
// Object.setPrototypeOf(obj, proto) // obj는 proto를 부모 prototype으로 삼아라
// obj.sayHi(); // 출력가능


// // 또는 prototype chaining
// var 부모 = { name : 'kim' }
// var 자식 = Object.create(부모)
// var 손자 = Object.create(자식)

// 하지만 요즘은 prototype대신 Class쓰면 됨 ; contstructor는 일반 함수랑 헷갈리니까

function Students(name, age) {
    this.name = name,
    this.age = age
    this.sayHi = function() {
        console.log(`안녕, 나는 ${this.name}이야`)
    }
};

// Class: 대문자로 이름 시작, contstrutor, prototype 이쁘게 바꿔주는 문법

class User {
    constructor(name, phone){  // 사실 고정된 값이면 이렇게 안써도됨. 단, 파라미터 입력시 이렇게 작성 or object생성시 1회 실행용 코드
        this.name = name,
        this.phone = phone // 필드
    }
    // name = '특정 값'
    // phone = '특정 값'
    printAll() {  // 메소드(클래스내 정의된 함수)
        console.log(this.name + this.phone)
        }    
}

var user1 = new User('kim', '1234')



// class를 복사하려면? -> extends = 상속, inheritance

class SellerUser extends User {   // 유저 클래스 상속 (메소드 포함)
    constructor(name, phone) {
        super(name, phone)  // 부모 class의 constructor 연결부분
        this.company = 'samsung'
    }
    printAll2() { 
        super.printAll() // 메소드 복붙하면서 수정할 때

    } 
}

/*
class 장점: 비슷한 용도의 함수(매소드) 모아서 정리정돈, 상속
class 단점: 함수 정리정돈하는거는 파일 util로 뺴고 공통함수로 써도 되는데? + 상속 너무 복잡하면 문제 -> composition 사용(필요한 것만 조합)
*/

class Heal {
  heal() {
    console.log("대충치유로직");
  }
} 
// class Healer {
//   constructor() {
//     this.ability1 = new Heal()
//   }
//   healSkill() {
//     this.ability1.heal()
//   }
// }

// dependeny injection
class Healer {
    constructor(a) {
        this.ability1 = a
    }
    healSkill() {
        this.ability1.heal(); 
    }
}
var a = new Heal(); 
var healer = new Healer(a);

// JS는 프레임워크가 권장하는대로 코드를 짜면 됨 (객체지향 집착 X)
728x90
반응형