October 16, 2021
const circle = {}; // using object literal syntax{})를 객체 리터럴 구문이라고 한다.const circle = {
radius: 1,
location: {
x: 1,
y: 1
},
draw: function() {
console.log('draw');
}
};circle 객체는 Properties로 radius와 location가 있고 Methods로 draw가 있다.circle.draw(); // 출력 결과 : draw.)으로 객체의 Properties 및 Methods에 접근할 수 있다.Bad Example
const circle1 = {
radius: 1,
location: {
x: 1,
y: 1
},
draw: function() {
console.log('draw');
}
};
const circle2 = {
radius: 2,
location: {
x: 2,
y: 2
},
draw: function() {
console.log('draw');
}
};Good Example - Using Factory
// Factory Function
function createCircle(radius, x, y) {
return {
radius,
location: {
x,
y
},
draw: function() {
console.log('draw');
}
};
}
const circle1 = createCircle(1, 1, 1);
const circle2 = createCircle(2, 2, 2);createCircle이라는 함수를 생성했다. 이 함수는 객체를 반환하고 객체 내의 속성은 함수의 매개변수로 받아오도록 처리한다.// Constructor Function
function Circle(radius, x, y) {
this.radius = radius;
this.location = {
x,
y
}
this.draw = function() {
console.log('draw');
}
}
const myCircle = new Circle(1, 1, 1);
console.log(myCircle.radius); // 1{})를 생성하도록 하고 함수 내 this는 이 빈 객체를 가리키게 된다.this가 이 빈 객체를 가리키고 이 빈 객체에 this.radius 와 같은 방식으로 Properties와 Methods를 추가하는 것이다.return this를 하게 된다.myCircle에 할당하고 있기 때문에 myCircle.radius 을 출력하면 정상적으로 1이 출력된다.const badCircle = Circle(2, 2, 2);와 같이 작성했다면 함수 내 this는 badCircle가 아닌 Window(브라우저 기준)가 된다.constructor 속성
console.log(myCircle.constructor); // f Circle(...) {...}
console.log(Circle.constructor); // f Object() {...}myCircle.constructor는 Circle 함수를 가리킨다.Circle.constructor는 자바스크립트에 내장된 함수인 Object 함수이다.function Circle(radius, x, y) {
this.radius = radius;
this.location = {
x,
y
}
this.draw = function() {
console.log('draw');
}
}
const myCircle = new Circle(1, 1, 1);Circle 함수는 사실 하나의 Object다.Circle. 을 입력하면 접근할 수 있는 멤버(methods, properties)들이 자동 추천 목록으로 뜬다.
(ex. apply, arguments, bind, call, caller, length, name, prototype, toString, …)
Circle 함수도 하나의 객체이므로 Constructor 속성을 가지고, 이 Constructor는 이 Circle을 생성할 때 사용된 함수를 가리킨다.Circle.constructor 을 출력해보면 ƒ Function() { [native code] } (자바스크립트에 내장된 Constructor인 function)가 출력된다.function Circle() {...} 와 같이 함수를 선언할 때, 자바스크립트 엔진은 function constructor을 이용해서 객체를 생성하게 된다.JavaScript에는 두 가지 타입 종류가 존재한다.
Value Types (Primitives)
Reference Types
Primitives
let x = 10;
let y = x;
x = 20;
console.log(x); // 20
console.log(y); // 10x와 y는 완전히 독립된 두 개의 변수이다.x에 10을 할당하고 그 이후에 y에 x를 할당한 후 x에 20으로 재할당하면 x는 20으로 변경되지만 y는 x의 변경과는 상관없이 여전히 10이다. Objects
let x = { value: 10 };
let y = x;
x.value = 20;
console.log(x.value); // 20
console.log(y.value); // 20x.value와 y.value는 모두 20이다.let y = x; 와 같이 y에 x를 할당하게 되면 참조 할당이 일어난다. 즉, 객체 자체가 복사되어 새로운 메모리에 할당되는 것이 아니라 해당 객체가 저장되어 있는 메모리의 주소값이 복사되는 것이다. x와 y는 동일한 객체를 가리키게 되고 x.value의 값을 변경하면 y.value의 값도 변경되는 것이다.
결론
Primitives are copied by their value - Example
let number = 10;
function increase(number) {
number++;
}
increase(number);
console.log(number); // 10;increase 함수를 호출할 때 함수에서 받은 number라는 매개변수는 코드 1행의 number와는 완전히 별개의 변수이다.number의 값을 증가시키더라도 1행의 number와는 상관이 없기 때문에 코드 마지막 행에서 number값을 출력하면 10이 출력된다. Objects are copied by their reference - Example
let obj = { value: 10 };
function increase(obj) {
obj.value++;
}
increase(obj);
console.log(obj.value); // 11;increase 함수를 호출할 때 함수에서 받은 obj라는 매개변수는 코드 1행의 obj와는 별개의 변수이지만 같은 객체 { value: 10 }을 가리킨다. (객체는 참조 복사가 되기 때문.)obj.value의 값을 증가시키면 1행의 obj도 같은 객체를 가리키고 있기 때문에 코드 마지막 행에서 obj.value를 출력하면 11이 출력된다.function Circle(radius) {
this.radius = radius;
this.draw = function() {
console.log('draw');
}
}
const circle = new Circle(10); // circle object 생성
circle.location = { x: 1 }; // location 속성 추가
console.log(circle); // { radius: 10, location: { x: 1 }, draw: f }
circle['name'] = 'c1';
console.log(circle); // { radius: 10, location: { x: 1 }, name: 'c1', draw: f }
delete circle['location'];
delete circle.name;.이나 [] 으로 접근/추가할 수 있다..)은 Brackets Notation([])보다 표기법이 심플하다.[])은 동적인 속성명으로 접근할 때 유용하다. ex) circle[propertyName]또한 Bracket([])은 유효한 식별자가 아닌 속성 이름을 사용할 때 유용하다.
circle.center-location과 같은 접근은 불가능하다.circle['center-location']과 같은 접근은 가능하다.delete Operator 를 사용하면 된다. for in loop
function Circle(radius) {
this.radius = radius;
this.draw = function() {
console.log('draw');
}
}
const circle = new Circle(10);
for (let key in circle) {
console.log('key is ' + key);
console.log('value is ' + circle[key]);
}circle[key]와 같이 접근하면 된다.Object.keys()
const keys = Object.keys(circle);
console.log(keys); // ["radius", "draw"]in operator
if ('radius' in circle) {
console.log('Circle has a radius')
}function Circle(radius) {
this.radius = radius;
this.defaultLocation = {
x: 0,
y: 0,
};
this.computeOptimumLocation = function() {
// ...
}
this.draw = function() {
this.computeOptimumLocation();
console.log('draw');
}
}
const circle = new Circle(10);
circle.defalutLocation = false; // Bad
circle.computeOptimumLocation(); // Badcircle.defaultLocation에 뜬금없이 false를 할당한다거나,draw 메소드 안에서만 호출 되기를 바라는 computeOptimumLocation 메소드를 직접적으로 호출하면 객체를 나쁜 상태로 만들 수 있다.Circle 함수에서 radius와 draw만 외부에서 접근 가능하도록 하고 defaultLocation과 computeOptimumLocation은 외부에서 접근 불가능하도록 해보자. function Circle(radius) {
this.radius = radius;
let defaultLocation = {
x: 0,
y: 0,
};
let computeOptimumLocation = function() {
// ...
}
this.draw = function() {
computeOptimumLocation();
console.log('draw');
}
}
const circle = new Circle(10);this.defaultLocation 대신 let defaultLocation과 같이 로컬 변수로 정의하면 함수 외부로부터 숨길 수 있다.defaultLocation과 computeOptimumLocation을 외부에서 직접 접근이 불가능하도록 만들고 싶기 때문에 로컬 변수로 변경했고draw 메소드 내에서 호출하고 있었던 this.computeOptimumLocation() 대신 computeOptimumLocation() 으로 변경했다.draw 메소드 내에서 computeOptimumLocation을 호출하면 Circle 외부에서 draw 메소드를 호출할 때 computeOptimumLocation이 정상적으로 실행되는데,위에서는 함수 외부에서 접근하지 못하도록 하는 방법으로 로컬 변수를 두었는데
어떻게 하면 함수 외부에서 수정은 못하도록 하고 읽기만 가능하도록 할 수 있을까?
function Circle(radius) {
this.radius = radius;
let defaultLocation = {
x: 0,
y: 0,
};
this.getDefaultLocation = function() {
return defaultLocation;
}
this.draw = function() {
console.log('draw');
}
}
const circle = new Circle(10);
console.log(circle.getDefaultLocation()); // { x: 0, y: 0 }defaultLocation이라는 변수는 Circle 함수 외부에서 직접적으로 접근은 불가능하지만getDefaultLocation이라는 함수를 통해서 (클로저 개념을 이용해) defaultLocation 변수를 조회할 수 있다. (수정은 불가능)function Circle(radius) {
this.radius = radius;
let defaultLocation = {
x: 0,
y: 0,
};
this.draw = function() {
console.log('draw');
}
Object.defineProperty(this, 'defaultLocation', {
get: function() {
return defaultLocation;
}
});
}
const circle = new Circle(10);
console.log(circle.defaultLocation); // { x: 0, y: 0 }get 이라는 이름의 key를 지정해주고 value로는 함수를 넣어준다.circle.defaultLocation과 같이 접근하면 이 get 함수가 호출되는 것이다. circle 객체를 출력 해보면 아래와 같이 새로운 property인 defaultLocation이 추가된 것을 볼 수 있다. 이것은 read-only 속성이다. 만약에 이 속성을 변경하고 싶다면 setters를 사용해야 한다.
function Circle(radius) {
this.radius = radius;
let defaultLocation = {
x: 0,
y: 0,
};
this.draw = function() {
console.log('draw');
}
Object.defineProperty(this, 'defaultLocation', {
get: function() {
return defaultLocation;
},
set: function(value) {
if (!value.x || !value.y) {
throw new Error('Invalid location.');
}
defaultLocation = value;
}
});
}
const circle = new Circle(10);
circle.defaultLocation = { x: 10, y: 20};
console.log(circle.defaultLocation); // { x: 10, y: 20 }