반응형
1. 객체를 만들 때 사용하는 방법 3가지
/**
* All about objects
*
* 객체를 선언할때 사용 할 수 있는 방법들
* 1) object를 생성해서 객체 생성 - 기본기 {}
* 2) class를 인스턴스화해서 생성 - class와 OOP
* 3) function을 사용해서 객체 생성
*/
const yuJin = {
name: '안유진',
year: 2003,
};
console.log(yuJin);
class IdolModel{
name;
year;
constructor(name, year){
this.name = name;
this.year = year;
}
}
console.log(new IdolModel('안유진', 2003));
// 생성자 함수
function IdolFunction(name, year){
this.name = name;
this.year = year;
}
const gaEul = new IdolFunction('가을', 2002);
console.log(gaEul);
결과는 아래와 같습니다.
{ name: '안유진', year: 2003 }
IdolModel { name: '안유진', year: 2003 }
IdolFunction { name: '가을', year: 2002 }
2. Property Attribute
/**
* Property Attribute
*
* 1) 데이터 프로퍼티 - 키와 값으로 형성된 실질적 값을 갖고있는 프로퍼티
* 2) 액세서 프로퍼티 - 자체적으로 값을 갖고 있지 않지만 다른 값을 가져오거나
* 설정할때 호출되는 함수로 구성된 프로퍼티
* 예를들면 getter와 setter
*/
const yuJin = {
name: '안유진',
year: 2003,
};
console.log(Object.getOwnPropertyDescriptor(yuJin, 'year'));
/**
* 1) value - 실제 프로퍼티의 값
* 2) writable - 값을 수정 할 수 있는지 여부. false로 설정하면 프로퍼티 값을
* 수정 할 수 없다.
* 3) enumerable - 열거가 가능한지 여부이다. for...in 룹 등을 사용 할 수 있으면
* true를 반환한다.
* 4) configurable - 프로퍼티 어트리뷰트의 재정의가 가능한지 여부를 판단한다.
* false 일 경우 프로퍼티 삭제나 어트리뷰트
* 변경이 금지된다. 단, writable이 true인 경우
* 값 변경과 writable을 변경하는건 가능하다.
*/
console.log(Object.getOwnPropertyDescriptor(yuJin, 'name'));
console.log(Object.getOwnPropertyDescriptors(yuJin));
const yuJin2 = {
name: '안유진',
year: 2003,
get age(){
return new Date().getFullYear() - this.year;
},
set age(age){
this.year = new Date().getFullYear() - age;
}
}
console.log(yuJin2);
console.log(yuJin2.age);
yuJin2.age = 32;
console.log(yuJin2.age);
console.log(yuJin2.year);
console.log(Object.getOwnPropertyDescriptor(yuJin2, 'age'));
Object.defineProperty(yuJin2, 'height', {
value: 172,
writable: true,
enumerable: true,
configurable: true,
})
console.log(yuJin2);
console.log(Object.getOwnPropertyDescriptor(yuJin2, 'height'));
yuJin2.height = 180;
console.log(yuJin2);
/**
* Writable
*/
Object.defineProperty(yuJin2, 'height', {
writable:false,
});
console.log(Object.getOwnPropertyDescriptor(yuJin2, 'height'));
console.log('-------------');
yuJin2.height = 172;
console.log(yuJin2);
/**
* Enumerable
*/
console.log(Object.keys(yuJin2));
for(let key in yuJin2){
console.log(key);
}
Object.defineProperty(yuJin2, 'name', {
enumerable:false,
});
console.log(Object.getOwnPropertyDescriptor(yuJin2, 'name'));
console.log('-------------');
console.log(Object.keys(yuJin2));
for(let key in yuJin2){
console.log(key);
}
console.log(yuJin2);
console.log(yuJin2.name);
/**
* Configurable
*/
Object.defineProperty(yuJin2, 'height', {
writable: true,
configurable: false,
});
console.log(Object.getOwnPropertyDescriptor(yuJin2, 'height'));
// Object.defineProperty(yuJin2, 'height', {
// enumerable: false,
// });
Object.defineProperty(yuJin2, 'height', {
value: 172,
//writable: true,
//enumerable: true,
//configurable: true,
});
console.log(Object.getOwnPropertyDescriptor(yuJin2, 'height'));
Object.defineProperty(yuJin2, 'height', { // 값 변경 못하게
writable: false,
});
console.log(Object.getOwnPropertyDescriptor(yuJin2, 'height'));
Object.defineProperty(yuJin2, 'height', {
writable: true,
});
실행 결과는 아래와 같아요.
{ value: 2003, writable: true, enumerable: true, configurable: true }
{ value: '안유진', writable: true, enumerable: true, configurable: true }
{
name: {
value: '안유진',
writable: true,
enumerable: true,
configurable: true
},
year: { value: 2003, writable: true, enumerable: true, configurable: true }
}
{ name: '안유진', year: 2003, age: [Getter/Setter] }
21
32
1992
{
get: [Function: get age],
set: [Function: set age],
enumerable: true,
configurable: true
}
{ name: '안유진', year: 1992, age: [Getter/Setter], height: 172 }
{ value: 172, writable: true, enumerable: true, configurable: true }
{ name: '안유진', year: 1992, age: [Getter/Setter], height: 180 }
{ value: 180, writable: false, enumerable: true, configurable: true }
-------------
{ name: '안유진', year: 1992, age: [Getter/Setter], height: 180 }
[ 'name', 'year', 'age', 'height' ]
name
year
age
height
{ value: '안유진', writable: true, enumerable: false, configurable: true }
-------------
[ 'year', 'age', 'height' ]
year
age
height
{ year: 1992, age: [Getter/Setter], height: 180 }
안유진
{ value: 180, writable: true, enumerable: true, configurable: false }
{ value: 172, writable: true, enumerable: true, configurable: false }
{ value: 172, writable: false, enumerable: true, configurable: false }
3. Immutable Object
/**
* Immutable Object
*/
const yuJin = {
name: '안유진',
year: 2003,
get age(){
return new Date().getFullYear() - this.year;
},
set age(age){
this.year = new Date().getFullYear() - age;
}
}
console.log(yuJin);
/**
* Extensible
*/
console.log(Object.isExtensible(yuJin));
yuJin['position'] = 'vocal';
console.log(yuJin);
Object.preventExtensions(yuJin);
console.log(Object.isExtensible(yuJin));
yuJin['groupName'] = '아이브';
console.log(yuJin);
delete yuJin['position'];
console.log(yuJin);
/**
* Seal
*/
const yuJin2 = {
name: '안유진',
year: 2003,
get age(){
return new Date().getFullYear() - this.year;
},
set age(age){
this.year = new Date().getFullYear() - age;
}
}
console.log(yuJin2);
console.log(Object.isSealed(yuJin2)); // false
Object.seal(yuJin2); // configurable: false
console.log(Object.isSealed(yuJin2));
yuJin2['groupName'] = '아이브'; // 추가 안됨
console.log(yuJin2);
delete yuJin2['name']; // 삭제 안됨
console.log(yuJin2);
Object.defineProperty(yuJin2, 'name', {
writable: false,
});
console.log(Object.getOwnPropertyDescriptor(yuJin2, 'name'));
/**
* Freezed
*
* 읽기 외에 모든 기능을 불가능하게 만든다.
*/
const yuJin3 = {
name: '안유진',
year: 2003,
get age(){
return new Date().getFullYear() - this.year;
},
set age(age){
this.year = new Date().getFullYear() - age;
}
}
console.log(Object.isFrozen(yuJin3));
Object.freeze(yuJin3);
console.log(Object.isFrozen(yuJin3));
yuJin3['groupName'] = '아이브';
console.log(yuJin3);
delete yuJin3['name'];
console.log(yuJin3);
// Object.defineProperty(yuJin3, 'name', {
// value: '코드팩토리',
// })
console.log(Object.getOwnPropertyDescriptor(yuJin3, 'name'));
const yuJin4 = {
name: '안유진',
year: 2003,
wonYoung: {
name: '장원영',
year: 2002,
},
};
Object.freeze(yuJin4);
console.log(Object.isFrozen(yuJin4));
console.log(Object.isFrozen(yuJin4['wonYoung']));
4. using function to create object
/**
* Using function to create objects
*/
function IdolModel(name, year){
if(!new.target){
return new IdolModel(name, year);
}
this.name = name;
this.year = year;
this.dance = function(){
return `${this.name}이 춤을 춥니다.`;
}
}
const yuJin = new IdolModel('안유진', 2003);
console.log(yuJin);
// console.log(yuJin.dance());
const yuJin2 = IdolModel('안유진', 2003); //undefined
console.log(yuJin2);
// console.log(global.name); // 사용하지 마라
const IdolModelArrow = (name, year)=>{
this.name = name;
this.year = year;
};
const yuJin3 = new IdolModelArrow('안유진', 2003);
5. Prototype chain
/**
* Prototype
*/
const testObj = {};
// __proto__ 모든 객체에 존재하는 프로퍼티다.
// class 강의에서 배울때 상속에서 부모 클래스에 해당되는 값이다.
console.log(testObj.__proto__);
function IdolModel(name, year) {
this.name = name;
this.year = year;
}
console.log(IdolModel.prototype);
// console.dir(IdolModel.prototype, {
// showHidden: true,
// });
// circular reference
console.log(IdolModel.prototype.constructor === IdolModel); //true
console.log(IdolModel.prototype.constructor.prototype === IdolModel.prototype); //true
const yuJin = new IdolModel('안유진', 2003);
console.log(yuJin.__proto__); // {}
console.log(yuJin.__proto__ === IdolModel.prototype); //true
console.log(testObj.__proto__ === Object.prototype); // true
console.log(IdolModel.__proto__ === Function.prototype); //true
console.log(Function.prototype.__proto__ === Object.prototype); // true
console.log(IdolModel.prototype.__proto__ === Object.prototype); //true
console.log(yuJin.toString()); //object object
console.log(Object.prototype.toString()); //object object
function IdolModel2(name, year) {
this.name = name;
this.year = year;
this.sayHello = function () {
return `${this.name}이 인사를 합니다.`;
}
}
const yuJin2 = new IdolModel2('안유진', 2003);
const wonYoung2 = new IdolModel2('장원영', 2002);
console.log(yuJin2.sayHello());
console.log(wonYoung2.sayHello());
console.log(yuJin2.sayHello === wonYoung2.sayHello);
console.log(yuJin2.hasOwnProperty('sayHello'));
function IdolModel3(name, year) {
this.name = name;
this.year = year;
}
IdolModel3.prototype.sayHello = function () {
return `${this.name}이 인사를 합니다.`;
}
const yuJin3 = new IdolModel3('안유진', 2003);
const wonYoung3 = new IdolModel3('장원영', 2004);
console.log(yuJin3.sayHello());
console.log(wonYoung3.sayHello());
console.log(yuJin3.sayHello === wonYoung3.sayHello);
console.log(yuJin3.hasOwnProperty('sayHello'));
IdolModel3.sayStaticHello = function () {
return '안녕하세요 저는 static method 입니다.';
}
console.log(IdolModel3.sayStaticHello());
/**
* Overriding
*/
function IdolModel4(name, year) {
this.name = name;
this.year = year;
this.sayHello = function () {
return '안녕하세요 저는 인스턴스 메서드입니다!';
}
}
IdolModel4.prototype.sayHello = function () {
return '안녕하세요 저는 prototype 메서드입니다!';
}
const yuJin4 = new IdolModel4('안유진', 2003);
// 프로퍼티 셰도잉 - class에서 override
console.log(yuJin4.sayHello());
/**
* getPrototypeOf, setPrototypeOf
*
* 인스턴스의 __proto__ 변경 vs 함수의 prototype 변경
*/
function IdolModel(name, year) {
this.name = name;
this.year = year;
}
IdolModel.prototype.sayHello = function () {
return `${this.name} 인사를 합니다.`;
}
function FemaleIdolModel(name, year) {
this.name = name;
this.year = year;
this.dance = function(){
return `${this.name}가 춤을 춥니다.`;
}
}
const gaEul = new IdolModel('가을', 2004);
const ray = new FemaleIdolModel('레이', 2004);
console.log(gaEul.__proto__);
console.log(gaEul.__proto__ === IdolModel.prototype);
console.log(Object.getPrototypeOf(gaEul) === IdolModel.prototype);
console.log(gaEul.sayHello());
console.log(ray.dance());
console.log(Object.getPrototypeOf(ray) === FemaleIdolModel.prototype);
// console.log(ray.sayHello());
Object.setPrototypeOf(ray, IdolModel.prototype);
console.log(ray.sayHello());
console.log(ray.constructor === FemaleIdolModel);
console.log(ray.constructor === IdolModel);
console.log(gaEul.constructor === IdolModel);
console.log(Object.getPrototypeOf(ray) === FemaleIdolModel.prototype);
console.log(Object.getPrototypeOf(ray) === IdolModel.prototype);
console.log(FemaleIdolModel.prototype === IdolModel.prototype);
FemaleIdolModel.prototype = IdolModel.prototype;
const eSeo = new FemaleIdolModel('이서', 2007);
console.log(Object.getPrototypeOf(eSeo) === FemaleIdolModel.prototype);
console.log(FemaleIdolModel.prototype === IdolModel.prototype);
6. Scope
/**
* Scope
*/
var numberOne = 20;
function levelOne(){
console.log(numberOne);
}
// levelOne();
function levelOne(){
var numberOne = 40;
console.log(numberOne);
}
// levelOne();
console.log(numberOne);
function levelOne(){
var numberOne = 40;
function levelTwo(){
var numberTwo = 99;
console.log(`levelTwo numberTwo : ${numberTwo}`);
console.log(`levelTwo numberOne : ${numberOne}`);
}
levelTwo();
console.log(`levelOne numberOne : ${numberOne}`);
}
levelOne();
console.log(numberOne);
// console.log(numberTwo);
/**
* JS -> Lexical Scope
*
* 선언된 위치가 상위 스코프를 정한다.
*
* Dynamic Scope
*
* 실행한 위치가 상위 스코프를 정한다.
*/
var numberThree = 3;
function functionOne(){
var numberThree = 100;
functionTwo();
}
function functionTwo(){
console.log(numberThree);
}
functionOne();
var i = 999;
for(var i = 0; i < 10; i++){
console.log(i);
}
console.log(`i in global scope : ${i}`)
i = 999;
// block level scope
for(let i = 0; i < 10; i++){
console.log(i);
}
console.log(`i in global scope : ${i}`);
/**
* var 키워드는 함수 레벨 스코프만 만들어낸다.
*
* let, const 키워드는 함수 레벨 스코프와 블록 레벨 스코프를 만들어낸다.
*/
7. this
/**
* this
*
* JS는 Lexical Scope를 사용하기때문에 함수의 상위 스코프가
* 정의 시점에 평가된다.
*
* *****하지만 this 키워드는 바인딩이 객체가 생성되는 시점에 결정된다.
*/
const testFunction = function(){
return this;
}
console.log(testFunction());
console.log(testFunction() === global);
const yuJin = {
name: '안유진',
year: 2003,
sayHello: function(){
return `안녕하세요 저는 ${this.name}입니다.`;
},
}
console.log(yuJin.sayHello());
function Person(name, year){
this.name = name;
this.year = year;
this.sayHello = function(){
return `안녕하세요 저는 ${this.name}입니다.`;
}
}
const yuJin2 = new Person('안유진', 2003);
console.log(yuJin2.sayHello());
Person.prototype.dance = function(){
function dance2(){
return `${this.name}이 춤을춥니다.`;
}
return dance2();
}
console.log(yuJin2.dance());
/**
* this 키워드가 어떤걸 가르키냐는 세가지만 기억하면된다.
*
* 1) 일반 함수 호출할땐 this가 최상위 객체 (global 또는 window)를 가리킨다.
* 2) 메서드로 호출할땐 호출된 객체를 가리킨다.
* 3) new 키워드를 사용해서 객체를 생성했을땐 객체를 가리킨다.
*/
/** this 할당 방법
* 1) apply()
* 2) call()
* 3) bind()
*/
function returnName(){
return this.name;
}
console.log(returnName()); // Global 할당으로 undefined 출력
const yuJin3 = {
name: '안유진',
}
console.log(returnName.call(yuJin3)); // 안유진 yugin3에 바인딩
console.log(returnName.apply(yuJin3));// 안유진
/**
* 1) call -> 컴마를 기반으로 아규먼트를 순서대로 넘겨주고
* 2) apply -> 아규먼트를 리스트로 입력해야한다.
*/
function multiply(x, y, z){
return `${this.name} / 결과값 : ${x * y * z}`;
}
console.log(multiply.call(yuJin3, 3, 4, 5)); // 안유진 / 결과값 60
console.log(multiply.apply(yuJin3, [3, 4, 5])); // 안유진 / 결과값 60
/**
* bind()
*/
const laterFunc = multiply.bind(yuJin3, 3, 4, 5);
console.log(laterFunc);
console.log(laterFunc()); // 안유진 / 결과값 60
8-1. Execution Context
<script>
function one(){
console.log('run one');
console.log('run one finished');
}
function two(){
console.log('run two');
one();
console.log('run two finished');
}
function three(){
console.log('run three');
two();
console.log('run three finished');
}
three();
</script>
8-2. Execution Context
<script>
var number1 = 20;
var number2 = 30;
function multiply(x, y) {
var result = x * y;
return result;
}
var result1 = multiply(number1, number2);
var result2 = multiply(100, 200);
</script>
9-1. Closure
/**
* Closure
*
* A closure is the combination of a function and the lexical
* environemnt within which that function was declared
*
* "클로저는 어떤 함수와 해당 함수가 선언된 렉시컬 환경의 조합이다."
*
* "상위 함수보다 하위 함수가 더 오래 살아있는 경우를 closure라고 한다."
*/
function getNumber() {
var number = 5;
function innerGetNumber() {
return number;
}
return innerGetNumber();
}
// console.log(number);
// console.log(getNumber());
function getNumber() {
var number = 5;
function innerGetNumber() {
return number;
}
return innerGetNumber;
}
const runner = getNumber();
console.log(runner);
console.log(runner());
/**
* 1) 데이터 캐싱
*/
function cacheFunction() {
// 아래 계산은 매우 오래걸린다는 가정을 했을때
var number = 10 * 10;
function innerCacheFunction(newNumb){
return number * newNumb;
}
return innerCacheFunction;
}
const runner2 = cacheFunction();
console.log(runner2(10));
console.log(runner2(20));
function cacheFunction2(){
var number = 99;
function increment(){
number ++;
return number;
}
return increment;
}
const runner3 = cacheFunction2();
console.log(runner3()); //100
console.log(runner3()); //101
console.log(runner3());
console.log(runner3());
console.log(runner3());
console.log(runner3());
console.log(runner3()); //106
/**
* 3) 정보 은닉
*/
function Idol(name, year){
this.name = name;
var _year = year;
this.sayNameAndYear = function(){
return `안녕하세요 저는 ${this.name}입니다. ${_year}에 태어났습니다.`;
}
}
const yuJin = new Idol('안유진', 2003);
console.log(yuJin.sayNameAndYear());
console.log(yuJin.name); //안유진
console.log(yuJin._year); //undefined
9-2. Closure Example
<script>
function getNumber(){
var number = 5;
function innerGetNumber(){
return number;
}
return innerGetNumber;
}
var runner = getNumber();
console.log(runner());
</script>
반응형
'개발자 > Web' 카테고리의 다른 글
자바스크립트 기본 문법 강의 6 Async Programming (3) | 2024.10.17 |
---|---|
소스 코드가 포함된 50개의 자바스크립트 프로젝트 (3) | 2024.10.16 |
자바스크립트 기본 문법 강의 4 Class and OOP (2) | 2024.10.15 |
모든 자바스크립트 개발자가 알아야 할 33가지 기본 사항 (12) | 2024.10.15 |
50일 동안 50개의 프로젝트 - HTML/CSS 및 자바스크립트 (3) | 2024.10.01 |
모든 자바스크립트 개발자가 알아야 하는 33가지 개념 (8) | 2024.09.29 |
자바스크립트 기본 문법 강의 3 (3) | 2024.09.29 |
자바스크립트 기본 문법 강의 1 (16) | 2024.09.29 |
더욱 좋은 정보를 제공하겠습니다.~ ^^