// let user = new Object();
// let user = {};
// 중괄호 {...}안에는 키:값 쌍으로 구성된 프로퍼티가 들어감
// let user = {
// name : "John",
// age : 30
// };
// 1번째 user 객체에서 name 속성의 값을 얻고 싶다고 가정하면
// user.name 이라고 작성가능
// 이 경우 name 은 직접적으로 속성 이름으로 사용
// 2번째
// 때로는 객체의 속성 이름을 동적으로 결정해야 할 때가 존재
2번째의 경우
let user = {
name: "John",
age: 30,
sayHi() {
// 'this'는 '현재 객체'를 나타냅니다.
alert(this.name);
}
};
user.sayHi(); // John
// 메서드 내부에서 this 키워드를 사용하면 객체에 접근 가능하다.
// 참조에 의한 객체 복사
// let message = "hello";
// let phrase = message;
위 예시를 실행하면 두 개의 독립된 변수에 각각 문자열 hello 가 저장된다.
// let user = {
// name : "john"
// };
위 예시는 객체는 메모리 내 어딘가에 저장되고 변수 user 엔 객체를 참조할수 있는 값이 저장된다.
let user = { name: "John" };
let admin = user; // 참조값을 복사함
변수는 두 개이지만 각 변수엔 동일 객체에 대한 참조 값이 저장된다.따라서 객체에 접근하거나 객체를 조작할 땐 여러 변수를 사용할 수 있다.
let user = { name: 'John' };
let admin = user;
admin.name = 'Pete'; // 'admin' 참조 값에 의해 변경됨
alert(user.name); // 'Pete'가 출력됨. 'user' 참조 값을 이용해 변경사항을 확인함
// 객체를 서랍장에 비유하면 변수는 서랍장을 열 수 있는 열쇠라고 할수 있다. // 서랍장은 하나 서랍장을 열수 있는 열쇠는 두개인데 // 그 중하나 (admin)을 사용해 서랍장을 열어 정돈한 후 또 다른 열쇠로 서랍장을 열어 // 정돈된 내용을 볼수 있다.
// 참조에 의한 비교
// 객체 비교시 동등 연산자 == 와 일치 연산자 ===는 동일하게 동작
// 다른 예시를 살펴보자 두 객체 모두 비어있다는 점에서 같아 보이지만
// 독립된 객체이기 때문에 일치 동등 비교하면 거짓이 반환된다.
// let a = {};
// let b = {}; // 독립된 두 객체
// alert( a== b); // false;
// 메서드와 this
● 메서드 내부에서 this 선언
let user = {
name: "John",
age: 30,
sayHi() {
// 'this'는 '현재 객체'를 나타냅니다.
alert(this.name);
}
};
user.sayHi(); // John
// 메서드 내부에서 this 키워드를 사용하면 객체에 접근 가능하다.
// 여기까지는 this 대신 user를 대입해도 정상 작동하지만
let user = {
name: "John",
age: 30,
sayHi() {
alert( user.name ); // Error: Cannot read property 'name' of null
}
};
let admin = user;
user = null; // user를 null로 덮어씁니다.
admin.sayHi(); // sayHi()가 엉뚱한 객체를 참고하면서 에러가 발생했습니다.
// 이렇게 외부 변수를 사용해 객체를 참조하면 예상치 못한 에러가 발생한다. user를 복사해 다른 변수에 할당 admin=user하고 user는 전혀 다른 값으로 덮어썼다고 가정하면 sayhi() 는 원치 않는 값(null)을 참조할 것이다.
!! alert 함수가 user.name 대신 this.name을 인수로 받았다면 에러가 발생하지 않았을 것이다.
● 메서드 외부에서 this 선언
let user = { name: "John" };
let admin = { name: "Admin" };
function sayHi() {
alert( this.name );
}
// 별개의 객체에서 동일한 함수를 사용함
user.f = sayHi;
admin.f = sayHi;
// 'this'는 '점(.) 앞의' 객체를 참조하기 때문에
// this 값이 달라짐
user.f(); // John (this == user)
admin.f(); // Admin (this == admin)
admin['f'](); // Admin (점과 대괄호는 동일하게 동작함)
user.f()와 admin.f() 는 f라는 속성을 가진 객체 user와 admin에서 메서드를 호출하는 것이다.
f는 sayHi () 함수를 할당받은 속성이다. 따라서 user.f ()는 user 객체의 f 속성에 할당된 함수인 sayhi()를 호출하게 되고
admin.f()는 admin 객체의 f 속성에 할당된 함수인 sayhi()를 호출하게 된다.
기존 user 객체에 f라는 속성을 가진 함수를 추가한다는뜻
// new 연산자와 생성자 함수
// 생성자 함수와 일반 함수에 기술적인 차이는 없지만
// 다만 생성자 함수는 아래 두 관례를 따른다.
1. 함수 이름의 첫 글자는 대문자로 시작
2. 반드시 new 연산자를 붙여 실행
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("보라");
alert(user.name); // 보라
alert(user.isAdmin); // false
this.name = name 구문은 생성된 객체의 name 속성을 name 매개변수로 전달된 값으로 설정하고 this.isAdmin = false는 생성된 객체의 isAdmin 속성을 false로 설정한다.
그 후 new USer("보라")로 객체를 생성하면 User 함수가 호출되어 새로운 객체가 생성된다. name 매개변수에는 "보라"가 전달되어 user 객체의 name 속성이 "보라"로 설정된다.
또한 isAdmin 속성은 기본적으로 false로 설정되므로 user.isAdmin은 false를 반환한다.
따라서 첫 번째 alert(user.name)은 "보라"를 출력하고 두 번째 alert(user.isAdmin)은 false를 출력한다.
예시를 이용해 new User(...)가 실행되면 무슨 일이 일어나는지 살펴보자
function User(name) {
// this = {}; (빈 객체가 암시적으로 만들어짐)
// 새로운 프로퍼티를 this에 추가함
this.name = name;
this.isAdmin = false;
// return this; (this가 암시적으로 반환됨)
}
이제 let user = new User("보라")는 아래 코드를 입력한 것과 동일하게 동작한다.
let user = {
name: "보라",
isAdmin: false
};
new User("보라") 이외에도 new User("호진") , new User("지민") 등을 이용하면 손쉽게 사용자 객체를 만들 수 있습니다.
/ 특수 기호 // 특수 기호// 줄 바꿈 문자(newline character)라 불리는 특수기호 \n을 사용(여러 줄 문자열)
let guestList = "손님:\n * John\n * Pete\n * Mary";
alert(guestList); // 손님 리스트를 여러 줄에 걸쳐 작성함
// 부분 문자열 찾기
str.indexOf
// 첫번째 방법은 str.indexOf(substr,pos) 메서드를 이용하는 것
let str = 'Widget with id';
alert( str.indexOf('Widget') ); // 0, str은 'Widget'으로 시작함
alert( str.indexOf('widget') ); // -1, indexOf는 대·소문자를 따지므로 원하는 문자열을 찾지 못함
alert( str.indexOf("id") ); // 1, "id"는 첫 번째 위치에서 발견됨 (Widget에서 id)
● index에서 widget 처음 문자열 바로 등장하니까 index 0번이고
● indexOf("id") 부분에서 id는 왜 12가 아니고 1이나면 widget에서 id 한번나왔고 그다음 id가 있기 때문
let str = 'Widget with id';
alert( str.indexOf('id', 2) ) // 12
● 공백 포함해서 id는 12번째에서 시작된다.
● 코드 분석
let str = 'As sly as a fox, as strong as an ox';
let target = 'as'; // as를 찾아봅시다.
let pos = 0;
while (true) {
let foundPos = str.indexOf(target, pos);
if (foundPos == -1) break;
alert( `위치: ${foundPos}` );
pos = foundPos + 1; // 다음 위치를 기준으로 검색을 이어갑니다.
}
- while(true)를 실행 이 루프는 무한히 실행된다.
- str에서 target을 pos 위치(0)부터 검색한다.
- alert()를 사용하여 foundPos의 위치를 출력한다.
- foundPos가 -1인 경우 (즉 target이 더이상 발견되지 않는 경우) 루프를 종료한다.
● 코드 분석
let str = "As sly as a fox, as strong as an ox";
let target = "as";
let pos = -1;
while ((pos = str.indexOf(target, pos + 1)) != -1) {
alert( `위치: ${pos}` );
}
// 배열
// 배열선언
let arr = new Array();
let arr = [];
// 각 배열 요소엔 0부터 시작하는 숫자(인덱스)가 매겨져 있다. 이 숫자들은 배열 내 순서를 나타낸다.
배열 내 특정 요소를 얻고 싶다면 대괄호 안에 순서를 나타내는 숫자인 인덱스를 넣어주면 된다.
위의 코드에서 fruits 배열에는 요소가 하나만 있지만 요소의 인덱스가 123이므로 배열의 길이는 124가 된다.
ex) 배열에 4개의 요소가 있고 인덱스의 최댓값이 3이라면 배열의 길이는 4가 된다.
마지막 요소의 인덱스는 3이지만, 인덱스는 0부터 시작하기 때문에 길이는 3+1인 4가 된다.
// 구조 분해 할당(객체와 배열은 자바스크립트에서 가장 많이 쓰이는 자료 구조이다)
// 언제 사용하냐?
// 개발을 하다 보면 함수에 객체나 배열을 전달해야 하는 경우가 생기곤 한다.
// 가끔은 객체나 배열에 저장된 데이터 전체가 아닌 일부만 필요한 경우가 생기곤 한다.
// 이럴때 객체나 배열을 변수로 '분해'할 수 있게 해주는 특별한 문법인 구조분해할당(desctructiong assignment)을 사용 할수있다.
배열 분해하기 배열이 어떻게 변수로 분해되는지 예제를 통해 살펴보자.
// 이름과 성을 요소로 가진 배열
let arr = ["Bora", "Lee"]
// 구조 분해 할당을 이용해
// firstName엔 arr[0]을
// surname엔 arr[1]을 할당하였습니다.
let [firstName, surname] = arr;
alert(firstName); // Bora
alert(surname); // Lee
... 로 나머지 요소 가져오기
let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
alert(name1); // Julius
alert(name2); // Caesar
// `rest`는 배열입니다.
alert(rest[0]); // Consul
alert(rest[1]); // of the Roman Republic
alert(rest.length); // 2
배열 앞쪽에 위치한 값 몇 개만 필요하고 그 이후 이어지는 나머지 값들은 한데 모아서 저장하고 싶을때가 있다.
이럴 때는 점 세 개 ...를 붙인 매개변수 하나를 추가하면 나머지 (rest) 요소를 가져올수 있다.
객체 분해하기
let options = {
title: "Menu",
width: 100,
height: 200
};
let {title, width, height} = options;
alert(title); // Menu
alert(width); // 100
alert(height); // 200
● let {title,width,height} = options 에서 중괄호안에 순서는 중요하지 않고 중요한 것은 변수 이름과 (options) 객체의 속성 이름이 일치하는지 여부
● 여기서 alert(title)하면 왜 Menu가 추출되느냐 하면 객체 디스트럭처링을 통해 options 객체의 title 속성의 값이 title 변수에 할당되었기 때문이다.
let {title, width, height} = options; 구문을 통해 options 객체의 title 속성의 값인 "Menu"가 title 변수에 할당됩니다.