들어가기
중급자라면 이정도는 알고 있으면 좋다고 생각하는 부분을 모았습니다. 저도 다시 공부하는 기분으로 정리했습니다.
작성자: ospace114@empal.com, http://ospace.tistory.com/
함수
함수 호이스팅
호이스팅(hoisting, 끌어올림)은 코드 실행 전에 함수, 변수, 클래스, 선언문 들이 맨위로 이동하는 과정이다. 예를 들어 함수 선언 전에 함수를 호출할 수 있는 것이다.
f(); // 선언 전에 호출 가능
function f() { ... }
함수 스코프
let은 정의 전까지 존재하지 않지만, var은 스코프(Scope) 안에 어디든지 사용 가능하다.
var로 선언한 변수는 호이스팅(hoisting, 끌어올림)이라는 메커니즘을 따른다. 이는 선언만 가져올뿐 할당은 가져오지 않는다.
console.log(x); // referece 에러 발생
let x = 3;
console.log(x); // undefined
var x = 3;
이로 인해 var보다 let이 더 안전한 코딩이 될 수 있다.
클로저
클로저(Closure)는 주변 상태에 대한 참조와 함수에 대한 조합이다. 즉, 외부 함수의 데이터를 그 데이터를 조작하는 내부 함수를 연관시켜서 실행하게 해준다. 그렇기 때문에 함수가 선언되는 시점에 데이터가 어떤 범위에 있는지 신중하게 확인해야 한다.
let globalFunc;
{
let blockVar = 'a';
globalFunc = function() {
console.log(blockVar);
}
}
globalFunc(); // 'a'
const f = (function() {
let count = 0;
return function() {
return `called ${++count} time(s)`;
}
})();
f(); // called 1 time(s)
f(); // called 2 time(s)
배열
임의 위치에 추가/제거
let arr = [1, 2, 3];
arr.splice(1, 0, 5, 6]; // arr = [1, 5, 6, 2, 3]
arr.splice(1, 2); //arr = [1, 2, 3]
배열 안에 요소 교체
let arr = [1, 2, 3, 4];
arr.copyWithin(1, 2); // arr = [1, 3, 4, 4]
arr.copyWithin(2, 0, 2); // arr = [1, 3, 1, 3]
arr.copyWithin(0, -3, -1) // arr = [3, 1, 1, 3]
특정 값으로 채우기
const arr = new Array(5).fill(1); // arr = [1, 1, 1, 1, 1]
arr.fill('a'); // arr = ['a', 'a', 'a', 'a', 'a']
arr.fill('b', 1); // arr = ['a', 'b', 'b', 'b', 'b']
arr.fill('c', 2, 4); // arr = ['a', 'b', 'c', 'c', 'b']
Symbol
심볼은 많이 사용하지 않은 기능 중에 하나이지만, 잘 사용하면 훌륭한 키로 사용할 수 있다.
const SYM = Symbol();
const o = { a:1, b:2, c:3, [SYM]:4 };
for(let prop in o) {
if(!o.hasOwnProperty(prop)) continue;
console.log(`${prop}:${o[prop]}`);
}
Object.keys(o).forEach(prop => console.log(`${prop}: ${o[prop]}`));
클래스
클래스는 함수 확장에 대한 syntax sugar이다. 일반적인 OOP의 클래스와는 차이가 있다. 그러나 알고 있으면 유용하기에 간단하게 정리해보았다.
간단한 클래스 생성
class Car {
constructor() {
}
}
const car1 = new Car();
const car2 = new Car();
console.log(car1 instanceof Car); // true
console.log(car1 instanceof Array) // false
클래스에 속성과 메소드 추가
class Car {
constructor(make, model) {
this.make = make;
this.model = model;
this.useGears = ['P', 'N', 'R', 'D'];
this.useGear = this.useGears[0];
}
shift(gear) {
if(!~this.useGears.indexOf(gear))
throw new Error(`Invalid gear: ${gear}`);
this.useGear = gear;
}
}
const car1 = new Car('Tesla', 'Model s');
car1.shift('D');
console.log(car1.useGear);
메소드 수정 방지
class Car {
constructor(make, model) {
this.make = make;
this.model = model;
this._useGears = ['P', 'N', 'R', 'D'];
this._useGear = this._useGears[0];
}
get useGear() { return this._useGear; }
set useGear(value) {
if(!~this._useGears.indexOf(value))
throw new Error(`Invalid gear: ${value}`);
this._useGear = value;
}
shift(gear) { this.useGear = gear; }
}
아직까지는 _useGear로 접근가능한 상태이다. 프로퍼티를 완벽하게 보호하려면,
const Car = (function() {
const carProps = new WeakMap();
class Car {
constructor(make, model) {
this.make = make;
this.model = model;
this._useGears = ['P', 'N', 'R', 'D'];
carProps.set(this, { useGear: this._useGears[0] });
}
get useGear() { return carProps.get(this).useGear; }
set useGear(value) {
if(!~this._useGears.indexOf(value))
throw new Error(`Invalid gear: ${value}`);
carProps.get(this).useGear = value;
}
shift(gear) { this.useGear = gear; }
}
return Car;
})();
클래스는 함수이다
function Car(make, model) {
this.make = make;
this.model = model;
this.useGears = ['P', 'N', 'R', 'D'];
this.useGear = this.useGears[0];
}
정적 메소드
class Car {
static getNextVin() {
return Car.nextVin++;
}
constructor(make, model) {
this.make = make;
this.model = model;
this.vin = Car.getNextVin();
}
}
Car.nextVin = 0;
상속
class Vehicle {
constructor() {
this.passengers = [];
}
addPassenger(p) {
this.passengers.push(p);
}
}
class Car extends Vehicle {
constructor() {
super();
}
deployAirbags() {
console.log("BWOOSH!");
}
toString() {
return 'in string';
}
}
const v = new Vehicle();
v.addPassenger("Frank");
v.passengers;
const c = new Car();
c.addPassenger("Alice");
// v.deployAirbags(); // Error: deployAirbags is not function
c.deployAirbags();
믹스인
상속과는 다른 기능을 확장하는 방법으로 실행시점에 필요할 때에 확장가능하다.
function makeInsurable(o) {
o.addInsurancePolicy = function(p) { this.insurancePolicy = p }
o.getInsurancePolicy = function() { return this.insurancePolicy }
o.isInsured = function() { return !!this.insurancePolicy }
}
class InsurancePolicy{};
const car1 = new Car();
makeInsurable(car1);
car1.addInsurancePolicy(new InsurancePolicy());
또는
makeInsurable(Car.prototype);
const car1 = new Car();
car1.addInsurancePolicy(new InsurancePolicy());
함수 이름 충돌 가능성이 있기에 Symbol을 사용한 믹스인이다.
const ADD_POLICY = Symbol();
const GET_POLICY = Symbol();
const IS_INSURED = Symbol();
function makeInsurable(o) {
o[ADD_POLICY] = function(p) { this[ADD_POLICY] = p };
o[GET_POLICY] = function() { return this[GET_POLICY] };
o[IS_INSURED] = function() { return !!this[IS_INSURED] };
}
참고
- 모질라 MDN
- Mark Pilgrim, Dive Into HTML5
- ES6은 ECMA-262 ECMAScript 2015 언어 명세
- JavaScript Weekly, http://javascriptweekly.com
- Node Weekly, http://nodeweekly.com
- HTML5 Weekln, http://html5weekly.com
- 악셀 라우슈마이어(es6관련), http://www.2ality.com
- Nolan Lawson(자바스크립트개발자), http://nolanlawson.com
- David Walsh(es6 generator), https://davidwalsh.name
- @kangax, http://perfectionkills.com
'3.구현 > HTML5&Javascript' 카테고리의 다른 글
[javascript] 객체 변경 감지 (0) | 2023.11.05 |
---|---|
[javascript] 자바스크립트 중급자는 이것만 알고가자 2 (2) | 2023.11.03 |
[node.js] gulp을 사용한 node.js 환경구성 (0) | 2023.10.24 |
[vue2] vue.draggable 사용하기와 v-treeview 적용 검토 (0) | 2023.10.21 |
[HTML5] 드래그 앤 드롭(drag and drop) (2) | 2023.10.21 |