1. script async vs defer
default
script 에 option 값을 주지 않고 html 파일을 실행하게 되면 위에서 아래로 순차적으로 코드가 실행된다.
위에서부터 HTML parsing을 하다가 중간에 script 코드가 있으면 parsing을 멈추고 해당 js를 fetching 하고, fetching이 끝나면 executing 하고 그 다음 다시 parsing을 시작한다.
=> page를 loading 하는데 시간이 오래 걸린다.
async
async는 boolean 값으로 위에 그림에서처럼 선언 하는 것만으로 true로 설정되어 사용할 수 있다.
HTML parsing과 js 파일을 병렬로 fetching하고, fetching이 완료되면 parsing을 멈추고 executing 하게 된다.
=> async를 선언하지 않았을 때보다는 loading 시간을 절약할 수는 있지만 parsing이 완전히 끝나기 전에 executing을 하기 때문에 자바스크립트 파일에서 DOM 요소를 조작한다고 가정하면, 조작해야하는 DOM 요소가 정의되어있지 않은 경우가 있을 수 있어 에러가 발생할 위험이 있다.
또한 복수의 script가 있을때, fetching이 끝나는 순서대로 executing 되기 때문에 script가 순서의존적으로 코딩되어 있으면 에러가 발생할 위험이 있다.
defer
defer 역시 async 와 마찬가지로 선언하는 것만으로 사용할 수 있다. defer는 async과 마찬가지로 parsing과 fetching이 병렬로 동시에 이루어지지만, HTML parsing이 완료된 후에 js가 순서대로 executing 된다.
=> 제일 효율적이고 안전한 방법
2. Operator
Increment and decrement operators
i.e.
let counter = 2;
const preIncrement = ++counter;
// preIncrement = counter; //2
// counter = counter + 1; //3
const postIncrement = counter++;
// counter = counter + 1; //4
// postIncrement = counter //4
Assignment operators
i.e.
let x = 3;
let y = 6;
x+=y; // x = x + y
x-=y; // x = x - y
x*=y; // x = x * y
x/=y; // x = x / y
3. Class와 Object
class는 붕어빵 틀과 같고 object는 틀을 사용하여 만든 붕어빵과 같다.
Class
i.e.
class person {
name;
age;
speak();
}
=> name, age와 같은 property와 그 value => 속성(field)
=> speak() 와 같은 함수 => 행동(method)
method는 들어있지 않고 field만 있는 class도 간혹 존재한다. => data class
template
- declare once
- no date in
① class declarations
i.e.
class Person {
constructor(name, age) { // constructor
this.name = name; // fields
this.age = age;
}
speak() { // methods
console.log(`${this.name}: hello!`};
}
}
//Object 생성
const ellie = new Person('ellie', 20);
console.log(ellie.name);
ellie.speak();
class라는 keyword를 사용하여 class를 생성하고, constructor(생성자)를 사용하여 object를 만들 때 필요한 data를 전달한다. 그리고 전달한 data를 class에 할당한다.
그리고 speak() 같은 method도 존재한다.
② Getter and Setter
i.e.
class User {
constructor(firstName, lastName, age) {
this.fisrstName = firstName;
this.lastName = lastName;
this.age = age;
}
get age() { // 값을 return
return this.age;
}
set age(value) { // 값을 설정 -> value를 받아와야 합니다.
this.age = value;
}
}
const user1 = new User('Steve', 'Jobs', -1);
console.log(user1.age);
Getter 를 정의하는 순간 class의 this.age는 메모리에 올라가 있는 data를 읽어 오는 것이 아니라 Getter를 호출하게 된다.
Setter 를 정의하는 순간 this.age의 value 값인 age는 메모리의 data를 할당하는 것이 아니라 Setter를 호출한다..
=> Setter에서 안에서 value를 this.age에 할당할 때 메모리의 값을 업데이트 하는 것이 아니라 다시 Setter를 호출하게 된다. 이게 무한정 반복되며 call stack size exceed 에러가 발생한다.
==> 이를 방지하기 위해 Getter와 Setter의 변수 이름을 수정해줘야 한다.(보통 변수명 앞에 언더바)
get age() {
return this._age;
}
set age(value) {
this._age = value;
}
Setter 설정
setter 를 정의하고 나면 아래와 같이 2가지 방법으로 조건을 설정할 수 있다.
①
set age(value) {
if (value < 0) {
throw Error('age can not be negative');
}
this._age = value;
}
------------------------------------------------------
②
set age(value) {
this._age = value < 0 ? 0 : value;
}
③ Fields (public, private)
최근에 추가된 방법
class Experiment {
publicField = 2;
#pribateField = 0;
}
const experiment = new Experiment();
console.log(experiment.publicField); // 2
console.log(experiment.privateField); //undefined
constructor(생성자)를 쓰지 않고 field를 정의할 수 있는데 그냥 정의하게 되면 public 즉,외부에서 접근이 가능하고 #을 붙이게 되면 private field로 class 내부에서만 값이 보여지고 정의되고 변경이 가능하지만 class 외부에서는 값을 읽을 수도 변경할 수도 없다.
최근에 추가된 것으로 아직 최신 브라우저에서도 지원하지 않으며 사용하려면 babel이 필요하다.
④ static properties and methods
class Article {
static publisher = 'Dream Coding';
constructor(articleNumber) {
this.articleNumber = articleNumber;
}
static printPublisher() {
console.log(Article.publisher);
}
}
const article1 = new Article(1);
const article2 = new Article(2);
//만약 static을 사용하지 않았다면 object를 사용하여 publisher 변수를 출력할 수 있었을 것 입니다.
console.log(article1.publisher); // undefined => static은 object마다 할당되는 것이 아니기 때문에
// 따라서 아래와 같이 class를 가지고 호출해야한다. method를 호출할 때 역시 마찬가지
console.log(Article.publisher); // Dream Coding
Article.printPublisher(); // Dream Coding
object 와 상관없이 class가 가지고 있는 고유한 값과 data와 관계 없이 동일하게 반복적으로 사용되는 method가 있다면 static keyword를 사용하여 object와 상관없이 class 자체에 연결되어 있다. -> 반복적으로 사용될 값과 method를 이렇게 처리하면 메모리 사용을 줄여줄 수 있다.
⑤ Inheritance
상속과 다형성
a way for one class to extend another class.
class Shape {
constructor(width, height, color) {
this.width = width;
this.height = height;
this.color = color;
}
draw() {
console.log(`drawing ${this.color} color of`);
}
getArea() {
return width * this.height;
}
}
class Rectangle extends Shape {}
class Triangle extends Shape {}
const rectangle = new Rectangle(20, 20, 'blue');
rectangle.draw();
console.log(rectangle.getArea()); // 400
const triangle = new Triangle(20, 20, 'blue');
triangle.draw();
console.log(triangle.getArea()); // 400
extends keyword를 사용하여 Rectangle class에 Shape class를 연장한다.
=> Shape에서 정의한 fields와 method가 자동으로 Rectangle에 포함된다. (Triangle 도 마찬가지)
다만, 여기서 getArea() 를 호출하면 rectangle과 triangle은 shape에서 정의된 method를 공유하고 있기 때문에 동일한 400이라는 value를 출력하지만 rectangle과 triangle의 면적을 구하는 공식은 다르다.
Overriding : class가 가지는 다형성
extends 된 class 공통으로 사용될 fields와 methods를 계속 공유하고 필요한 함수만 재정의해서 사용할 수 있다.
class Triangle extends Shape {
draw() {
super.draw(); // parent의 method도 호출되도록
console.log('🔺');
}
getArea {
return (width * this.height) / 2;
}
}
const triangle = new Triangle(20, 20, 'blue');
console.log(triangle.getArea()); // 200
또한 method를 재정의할 때 기존의 method를 받아온 상태에서 새롭게 코드를 추가하고자 한다면 위와 같이 사용하면 기존의 method 코드는 그대로 두고 내가 원하는 코드를 추가할 수 있다.
⑥ Class checking: instanceOf
Object는 class를 이용해서 만들어진 새로운 instance이다.
instanceOf 는 왼쪽의 object가 오른쪽의 class를 사용하여 만들어진 instance인지 아닌지 확인하는 것으로 True/False 값을 한다.
console.log(rectangle instanceof Rectangle); //true
console.log(triangle instanceof Rectangle); //false
console.log(triangle instanceof Triangle); //true
console.log(triangle instanceof Shape); //true
console.log(triangle instanceof Object); //true
triangle은 Shape을 상속하여 만든 object이다.
javascript에서 만든 object들을 javascript의 Object를 상속한 것 이다.
=> 모든 object들은 공통으로 존재하는 method들을 사용할 수 있다.
class Triangle extends Shape {
.
.
.
. // Object에 있는 toString이라는 함수를 overriding 할 수 있다.
toString() {
return `Triangle: color: ${this.color}`;
}
}
Object
instance of a class
- created many times
- data in
① Literals and properties
1. 'object literal' syntax
const obj1 = {};
2. 'object constructor' syntax
const obj2 = new Object();
Javascript는 dynamically typed laguage, 동적으로 type이 Runtime 때 결정된다. (runtime : 프로그램이 동작하고 있을 때)
const ellie = { name: 'ellie', age: 4};
print(ellie);
ellie.hasJob = true; // object를 생성한 후에도 property를 추가할 수 있습니다.
delete ellie.hasJob; // 이처럼 property를 제거할 수도 있습니다.
// 이러한 동작들이 가능하지만 이렇게 할 경우 object를 관리하는데 어려움이 있기 때문에
// 이렇게 하지 않는 편이 좋습니다.
object = { key : value };
object는 key와 value의 집합체 입니다.
② Computed properties
key should be always string
// object 내부의 data에 접근하는 방법
console.log(ellie.name);
console.log(ellie['name']); //key를 가지고 접근하는 방법
ellie['hasJob'] = true // 이처럼 property를 추가할 수도 있다.
** Q.언제 computed property 를 사용해야 할까??**
정확하게 어떤 key가 필요한지 모를 때, 즉 Runtime에서 결정될 때 computed property를 사용해야 한다.
const ellie = { name: 'ellie', age: 20 };
function printValue(obj, key) {
console.log(obj.key);
}
printValue(ellie, 'name'); //undefined
printValue(ellie, name); //undefined
=> printValue 함수에서 key는 사용자에게 input을 받아와서 출력해야하는 함수
코딩하는 시점에는 어떤 key를 받아올 지 알 수 없다.
runtime 될때 어떤 key를 받아올지 결정된다. ∴ computed property 를 사용해야 한다.
function printValue(obj, key) {
console.log(obj.[key]);
}
③ Property value shorthand
const person1 = { name: 'Bob', age:24 };
const person2 = { name: 'Steven', age:32 };
const person3 = { name: 'David', age:12 };
const person1 = new Person('Bob', 24);
const person2 = new Person('Steven', 32);
const person3 = new Person('David', 12);
이처럼 동일한 key와 value가 반복되는 object를 생성할 때 property value shorthand를 사용하여 간단하게 코딩할 수 있다.
④ Constructor function
function Person(name, age) {
this.name = name; // this = {};
this.age = age; // return this; 와 같다
};
추가적인 계산없이 순수하게 object를 생성하는 함수는 함수명의 첫글자를 대문자로 한다.
⑤ in operator : property existence check ( key in obj)
object 안에 key가 있는지 없는지 확인하는 operator
console.log('name' in ellie); //true
console.log('age' in ellie); //true
console.log('random' in ellie); //false
⑥ for.. in vs for..of
// for (key in obj)
for (key in ellie) {
console.log(key);
}
// for ( value of iterable)
const array = [1, 2, 4, 5];
for (value of array) {
console.log(value);
}
⑦ Cloning
Object.assign(dest, [obj1, obj2, obj3...])
const user = { name: 'ellie', age: 20 };
const user2 = user;
user2.name = 'coder';
console.log(user); // { name: 'coder', age: 20}
user2는 user와 같은 reference를 가리키고 있다. 따라서 user2에 접근하여 property를 변경하면 user2와 같은 reference를 가리키는 user의 property도 변경된다.
reference가 아닌 object의 data를 복사하는 방법
// old way
const user3 = {};
for (key in user) {
user3[key] = user[key];
}
console.log(user3); //{ name: 'ellie', age: 20 }
user3.name = "Dave";
console.log(user); // { name: 'ellie', age: 20 }
console.log(user3); // { name: 'Dave', age: 20 }
// new way => Object.assign()
const user4 = {};
Object.assign(user4, user)
console.log(user4); // { name: 'ellie', age: 20 }
// new way simplify
const user4 = Object.assign({}, user);
//another example
const fruit1 = {color: 'red'};
const fruit2 = {color: 'blue', size: 'big'};
const mixed = Obeject.assign({}, fruit1, fruit2);
console.log(mixed); // {color: 'blue', size: 'big'}
=> 여러가지 object를 반복해서 assign 하게 되면 뒤쪽 object의 data가 덮어씌워진다.
'JavaScript' 카테고리의 다른 글
JS | Promise ( Producer, Consumer) (0) | 2021.12.28 |
---|---|
JS | 비동기 처리의 시작 콜백 (0) | 2021.12.27 |
JS | Array (0) | 2021.12.22 |
JS | logical and data type (0) | 2021.12.20 |
JS | clock(digital) , add back to top button (0) | 2021.12.17 |