상세 컨텐츠

본문 제목

코드카데미 Javascript - 객체와 this, 게터 & 세터, 내장객체 메소드

IT/Javascript

by J KIMS 2020. 9. 26. 11:42

본문

반응형

Object literal 객체 리터럴

  • 객체는 keyvalue로 구성된다
  • key는 변수가 저장되는 장소의 이름이고 값value를 가짐

  • key-value들은 콤마(,)로 구분한다

let fasterShip = {
  color: 'silver',
  'Fuel Type': 'Turbo Fuel'
};

Accessing Properties 객체의 속성에 접근하는 법

👉 1. dot notation 점을 찍어 표현

 

객체의 속성에 접근해 다른 변수에 그 값을 할당하는 예시

let spaceship = {
  homePlanet: 'Earth',
  color: 'silver',
  'Fuel Type': 'Turbo Fuel',
  numCrew: 5,
  flightPath: ['Venus', 'Mars', 'Saturn']
};

// Access the value of numCrew from the spaceship
const crewCount = spaceship.numCrew;

// Assign the spaceship's flightPath property to planetArray
const planetArray = spaceship.flightPath;

 

👉 2. Bracket Notation

괄호 []를 이용해 객체의 값에 접근가능

💡 숫자, 스페이스, 특별 문자가 포함된 key에 접근할 때는 반드시 괄호를 사용해야함

 

괄호를 사용해서 객체의 속성에 접근하는 예시

key를 다른 변수에 저장한 후 괄호 안에는 그 변수를 쓰는 것도 가능

let spaceship = {
  'Fuel Type' : 'Turbo Fuel',
  'Active Mission' : true,
  homePlanet : 'Earth', 
  numCrew: 5
 };

// Assign the spaceship's 'Active Mission' property to a variable isActive
let isActive = spaceship['Active Mission'];

// Using bracket notation and the propName variable log the value of the 'Active Mission' property
let propName =  'Active Mission';
console.log(spaceship[propName]);

Property Assignment

 

객체는 mutable 하다 => 객체를 만든 후 새로운 속성을 추가하는 것이 가능하다

객체.속성 = 값; 혹은 객체[속성] = 값; 

  • 객체에 그 속성이 이미 존재한다면 새로운 값으로 대체한다

  • 그런 이름의 속성이 없다면 새로운 속성이 객체에 추가된다

💡 const로 만들어진 객체에 새로운 객체를 할당하는 것은 불가능하고 객체 안의 값을 바꾸는 것은 가능함

 

const spaceship = {type: 'shuttle'};
spaceship = {type: 'alien'}; // TypeError: Assignment to constant variable.
spaceship.type = 'alien'; // Changes the value of the type property
spaceship.speed = 'Mach 5'; // Creates a new key of 'speed' with a value of 'Mach 5'

 

💡 delete 연산자를 통해 객체의 속성을 삭제하는 것도 가능

 

const spaceship = {
  'Fuel Type': 'Turbo Fuel',
  homePlanet: 'Earth',
  mission: 'Explore the universe' 
};

delete spaceship.mission;  // Removes the mission property

Method 메소드

  • 객체 안에 있는 함수를 메소드라고 함

  • key는 메소드의 이름이고 value는 익명 함수의 함수 표현

  • ES6에서부터 콜론과 function 키워드를 생략할 수 있음

const alienShip = {
  invade: function () { 
    console.log('Hello! We have come to dominate your planet. Instead of Earth, it shall be called New Xaculon.')
  }
};

ES6 버전

const alienShip = {
  invade () { 
    console.log('Hello! We have come to dominate your planet. Instead of Earth, it shall be called New Xaculon.')
  }
};

Nested Objects

객체는 다른 객체들을 속성으로 가질 수 있다.

예를 들면 spaceship라는 객체에는 passengers, telescope, crew 등등의 다른 객체들이 들어있을 수 있다.

let spaceship = {
  // Assign an array of objects that has at least one key-value pair
  passengers: [{name: 'Space Cat'}, {name: 'JKim'}],
  telescope: {
    yearBuilt: 2018,
    model: "91031-XLT",
    focalLength: 2032 
  },
  crew: {
    captain: { 
      name: 'Sandra', 
      degree: 'Computer Engineering', 
      encourageTeam() { console.log('We got this!') },
     'favorite foods': ['cookies', 'cakes', 'candy', 'spinach'] }
  },
  engine: {
    model: "Nimbus2000"
  },
  nanoelectronics: {
    computer: {
      terabytes: 100,
      monitors: "HD"
    },
    'back-up': {
      battery: "Lithium",
      terabytes: 50
    }
  }
}; 

// Get the element in the 0th index of 'favorite foods' array
let capFave = spaceship.crew.captain['favorite foods'][0];

// Assign the first passenger of the spaceship
let firstPassenger = spaceship.passengers[0];

1. passengers 객체는 다른 객체들의 배열을 갖고 있는 것을 알 수 있음

2. capFave는 객체의 객체의 객체의 속성의 배열의 첫번째 값에 접근하는 예를 보여줌

(spaceship -> crew -> captain -> 'favorite foods' -> 'cookies')

 


Pass By Reference

객체는 함수의 인자로 넘겨주는 것이 가능하다.

컴퓨터는 함수의 파라미터가 그 객체를 저장하고 있는 메모리를 가리킨다고 해석하기 때문에 실제로 함수를 통해 객체의 값을 바꾸면 객체의 값이 바뀐다.

 

(말이 좀 이상한데 C언어에서 포인터 개념을 생각하면 쉬움. 함수에 배열의 이름을 넘겨주면 그 배열일 저장된 주소값을 넘겨주는 것과 같고 결국 함수 내부의 조작으로 실제 배열의 값을 조작하는게 가능한 것과 동일한 원리)

 

하지만 함수 내부에서 해당 객체에 새로운 객체를 할당하는 것은 불가능

 

💡 정리

1. 객체의 속성을 바꾸는 함수는 만들 수 있다

2. 객체에 새로운 속성을 추가하는 함수도 가능하다

2. 하지만 객체에 다른 객체를 재할당하는 함수는 만들 수 없다

 

let spaceship = {
  'Fuel Type' : 'Turbo Fuel',
  homePlanet : 'Earth'
};

// Function that sets object's 'Fuel Type' to 'avocado oil'
let greenEnergy = obj => obj['Fuel Type'] = 'avocado oil';
// Function that sets object's disabled property to true
let remotelyDisable = obj => obj.disabled = true;

// Call two functions
greenEnergy(spaceship);
remotelyDisable(spaceship);

// Confirm those properties were changed/added
console.log(spaceship);

 


Looping Through Objects

 

객체의 값을 루프를 통해 출력할 때는 for .. in .. 을 사용함

 

아래는 spaceship.crew라는 객체에 대해 루프를 돌린 것

주의할 점은 각 crewmember의 속성에 접근할 때는 가장 바깥 객체 루트부터 다 적어줘야 함

crewmember.name 이렇게 접근하는 건 불가능. crewmember는 그저 key 값이 저장된 변수에 불과함.

 

let spaceship = {
    crew: {
    captain: { 
        name: 'Lily', 
        degree: 'Computer Engineering', 
        cheerTeam() { console.log('You got this!') } 
        },
    'chief officer': { 
        name: 'Dan', 
        degree: 'Aerospace Engineering', 
        agree() { console.log('I agree, captain!') } 
        },
    medic: { 
        name: 'Clementine', 
        degree: 'Physics', 
        announce() { console.log(`Jets on!`) } },
    translator: {
        name: 'Shauna', 
        degree: 'Conservation Science', 
        powerFuel() { console.log('The tank is full!') } 
        }
    }
}; 

// Log a list of crew roles and names
for(let crewmember in spaceship.crew){
  console.log(`${crewmember} : ${spaceship.crew[crewmember].name}`);
}

// Log a list of crew names and degrees
for(let crewmember in spaceship.crew){
  console.log(`${spaceship.crew[crewmember].name} : ${spaceship.crew[crewmember].degree}`);
}

 

헷갈리면 이걸 보자

 

for (let variableName in outerObject.innerObject) {
  console.log(`${variableName}: ${outerObject.innerObject[variableName].propertyName}`)
};

this Keyword

const robot = {
  model:'1E78V2',
  energyLevel:100,
  provideInfo(){ 
    return `I am ${this.model} and my current energy level is ${this.   energyLevel}.`
  }
};

console.log(robot.provideInfo());

 여기서 this는 calling object인 객체 robot를 가리킨다. 만약에 this 없이 ${model}이라고 하면 referenceError가 뜨게 된다. 그 이유는 스코프 안에 있기 때문이다.

 

const goat = {
  dietType: 'herbivore',
  makeSound() {
    console.log('baaa');
  },
  diet: () => {
    console.log(this.dietType);
  }
};

goat.diet(); // Prints undefined

 

화살표 함수 안에서의 this전역 객체전역 스코프에 존재하는 객체를 가리킨다.

따라서 위의 경우에는 전역 객체에 dietType라는 속성이 없기 대문에 undefined가 뜨는 것이다.

 

전역 객체에 대한 MDN 문서 읽기

 

메소드를 만들때는 보통 함수 표현을 쓰는 것이 좋고 위와 같이 화살표 함수를 쓰고 싶다고 하면 this가 아닌 goat라고 객체 이름을 바로 적어주면 된다.

 


Privacy 

객체의 어떤 값은 변경 가능 하고 어떤 값은 그렇지 않음을 나타내기 위한 개념

key 이름 앞에 _를 적어주면 그 값은 변경하면 안된다는 의미. 그래도 값을 재할당하는 건 가능하다.

 

const bankAccount = {
  _amount: 1000
}

bankAccount._amount = 1000000;

Getter

get 키워드를 사용해 Getter 메소드를 만듬

Getter의 장점

  • 속성을 받아올때 데이터에 어떤 액션을 취할 수 있음

  • 조건에 따라 다른 값을 리턴할 수 있다

  • calling object의 내부 속성에 this를 사용해 접근할 수 있음

  • getter method를 호출할 때는 ()를 사용할 필요가 없음 e.g. 객체.getterMethod; 

  • 기능적으로 코드를 이해하기 더 쉬워짐

속성은 getter 메서드와 같은 이름을 쓸 수 없음 (call stack error)

 

const robot = {
  _model: '1E78V2',
  _energyLevel: 100,
  get energyLevel(){
    if(typeof(this._energyLevel) === 'number'){
      return `My current energy level is ${this._energyLevel}`;
    } else {
       return 'System malfunction: cannot retrieve energy level';
    }
  }
};

console.log(robot.energyLevel); // My current energy level is 100

 

Getter를 이용하면 어떤 형태로 가공해서 속성의 값을 출력하는 게 가능

 

Setter

setter는 getter랑 비슷한 이점들을 가지고 있음.

 

하지만 직접 값을 재할당 할 수 있다는 점이 다름. (??)

갑자기 이해안되기 시작.

 

const robot = {
  _model: '1E78V2',
  _energyLevel: 100,
  _numOfSensors: 15,
  get numOfSensors(){
    if(typeof this._numOfSensors === 'number'){
      return this._numOfSensors;
    } else {
      return 'Sensors are currently down.'
    }
  },
  set numOfSensors(num){
    if(typeof(num)==='number'&& num>=0){
      this._numOfSensors = num;
    } else {
      console.log('Pass in a number that is greater than or equal to 0');
    }
  }
  
};

robot.numOfSensors = 100;

console.log(robot.numOfSensors);


 

▷ Getter & Setter 관련 토론 읽기

 


Factory Functions

: 객체를 만드는 함수

예시)

robotFactory = (model, mobile) => {
  return {
    model: model,
    mobile: mobile,
    beep(){
      console.log('Beep Boop');
    }
  }
};

const tinCan = robotFactory('P-500', true);
tinCan.beep(); //Beep Boop

 

key와 value의 이름이 같으면 value를 생략할 수 있음 (destructuring)

 

robotFactory = (model, mobile) => {
  return {
    model,
    mobile,
    beep(){
      console.log('Beep Boop');
    }
  }
};

 

destructuring 테크닉은 속성의 값을 가져올 때도 사용할 수 있음

 

const robot = {
  model: '1E78V2',
  energyLevel: 100,
  functionality: {
    beep() {
      console.log('Beep Boop');
    },
    fireLaser() {
      console.log('Pew Pew');
    },
  }
};

// Reference robot.functionality
const {functionality} = robot;

// Shorcut to call the .beep() method
functionality.beep();

 

1. robot.functionality 를 functionality라는 변수에 저장할 때 위와 같이 적는게 가능

2. functionality가 robot.functionality를 참조하고 있기 때문에 beep() 메소드를 불러올때 functionality로 바로 메소드를 실행하는 게 가능

 


Built-in Object Methods

 

Object.keys(객체) : 객체가 담고 있는 key 값들을 배열로 반환함

Object.entries(객체) : 객체가 담고 있는 key-value를 배열로 반환

Object.assign(객체1, 객체2) : 객체2의 값을 객체 1에 합쳐서 리턴함 (객체1이 수정된다)

 

const robot = {
	model: 'SAL-1000',
  mobile: true,
  sentient: false,
  armor: 'Steel-plated',
  energyLevel: 75
};

// What is missing in the following method call?
const robotKeys = Object.keys(robot);

console.log(robotKeys);

// Declare robotEntries below this line:
const robotEntries = Object.entries(robot);

console.log(robotEntries);

// Declare newRobot below this line:

const temp =  {laserBlaster: true, voiceRecognition: true};
const newRobot = Object.assign(temp, robot);

console.log(newRobot);
반응형

관련글 더보기

댓글 영역