Explain event delegation
=> 이벤트 위임은 부모 DOM 요소에 이벤트 핸들러를 등록하여 자식 DOM 요소를 다루는 것을 말합니다.
자식요소에서 이벤트가 발생하고 이것이 이벤트 전파(캡처링 단계, 타깃 단계, 버블링 단계)의 버블링 단계를 통해 부모요소로 전파가 될때 이벤트 핸들러가 동작하게 됩니다.
이벤트 위임을 사용하게 되면 두가지 이점을 얻을 수 있습니다.
1. 성능을 향상 시킬수 있습니다. 만약 자식요소가 100개라면 100개 요소에 이벤트 핸들러를 등록해주어야 합니다. 이는 사용량의 저하를 초래합니다.
1. 자바스크립트에서 함수는 메모리를 잡아먹는 객체 입니다. 메모리를 많이 사용할수록 성능은 떨어집니다.
2. 이벤트 핸들러를 많이 할당하려면 DOM 접근도 많아집니다. 이는 웹의 접근성을 떨어 뜨릴수 있습니다.
2. 유지보수가 간편해 집니다.
고려해야 할 점은
1. 이벤트 핸들러 내부에서 동작을 수행하고자 하는 특정 DOM요소를 지칭해주어야 합니다. 이벤트 전파 경로에 있는 모든 DOM 요소들에 버블링이 일어나게 되므로 원하지 않는 DOM요소에서 이벤트 핸들러가 동작하게 될 수도 있습니다.
Explain how this works in Javascript
=> this는 자신이 속한 객체나 자신이 생성할 인스턴스를 가리키는 자기참조 변수 입니다.
자바스크립트에서 this는 함수의 호출을 기반으로 이루어 집니다(함수가 선언되는 위치가 아님).
함수가 호출되는 실행컨텍스트가 바로 this의 값이 됩니다.
같은 함수라도 this는 서로 다른 값을 나타낼 수 있습니다.
이는 this가 동적으로 binding 되기 때문입니다.
바인딩은 식별자와 값이 연결되는 과정을 말합니다.
1. 일반함수로서 호출
2. 메서드로서 호출
3. 생성자 함수로서 호출
4. Function.protype.call, apply, bind를 통한 호출
5. 이벤트 핸들러 함수에서 this는 이벤트 호출 객체를 가리킵니다(추가된 내용)
var foo = function () {
console.dir(this);
}
// 일반함수로서 호출되는 this는 window를 가리킵니다. node에서는 global, use strict 모드에서는 undefined
foo() // window
var obj = { foo };
// 메소드로서 호출될 경우 this는 호출한 객체를 가리킵니다.
obj.foo(); // obj { foo }
// 생성자 함수로서 호출될 경우 this는 생성될 인스턴스를 가리킵니다.
// 일반 함수에 new를 붙여서 호출하면 생성자 함수가 됩니다.
new foo() // foo 정보
var bar = { name: 'bar' }
// Function.prototype.call, apply, bind를 통해 명시적으로 this를 binding 할수 있습니다.
foo.call(bar) // name: 'bar' -> bar 객체에 대한 정보
foo.apply(bar) // name: 'bar' -> bar 객체에 대한 정보
foo.bind(bar)() // name: 'bar' -> bar 객체에 대한 정보
es2015(es6) 에서 등장한 화살표함수는 this에 대한 binding이 없습니다.
const Person = {
age: 0,
older() {
setTimeout(() => {
this.age++;
console.log(this.age);
}, 100)
}
}
const People = {
age: 0,
older() {
setTimeout(function(){
this.age++;
console.log(this.age);
}, 100)
}
}
Person.older() // 1
People.older() // NaN
People setTimeout의 this는 전역객체를 binding 합니다.(setTimeout 함수는 동기적으로 실행되는 것이 아닌 이벤트 큐에 들어갔다가 콜스택이 비면 이벤트 루프에 의해 큐에서 스택으로 넘어가서 실행이 된다.)
Person setTimeout내에 있는 화살표 함수는 자신의 this가 없습니다. 화살표 함수는 일반 변수의 스코프체인과 같이 this를 찾게 됩니다. 자신의 범위에 this가 없다면 바로 바깥 범위에서 this를 찾게 됩니다. 이때의 this는 메소드를 호출한 Person을 가리키게 될겁니다.
Explain how prototypal inheritance works
=> 두개의 코드중 아래의 코드는 프로토타입 상속을 이용하여 같은 기능을 구현한 것입니다.
첫번째 방법은 두개의 인스턴스는 name, say 두개의 property를 가지고 있습니다.
하지만 두번째 방법으로 생성한 두개의 인스턴스는 name property만 가지고 있습니다.
function Person(name){
this.name = name,
this.say = function() {
console.log(this.name)
}
}
const me = new Person('me');
const you = new Person('you');
me.say() // me
you.say() // you
function Person(name){
this.name = name
}
Person.prototype.say = function () {
console.log(this.name);
}
const me = new Person('me');
const you = new Person('you');
me.say() // me
you.say() // you
그러나 두 코드의 say 함수 호출결과는 같습니다.
이것이 가능한 이유는 Prototype 상속을 하였기 때문입니다.
자바스크립트의 객체는 __proto__라는 숨겨진 프로퍼티를 가집니다. 이 프로퍼티는 null 혹은 참조 객체를 가리키고 있습니다. 이 참조 대상을 프로토타입이라고 부릅니다.
자바스크립트에서는 호출된 메서드가 해당 객체에 존재하지 않을 경우 해당 객체의 프로토타입에 접근하여 메소드를 차례로 검색합니다.
그리고 발견하면 호출, 없으면 undefined를 출력하게 됩니다.
우리는 이것을 프로토타입 체인이라 부릅니다.
> new로 생성된 두개의 객체에서 __proto__를 통해 부모 객체에 접근할 수 있습니다.
What do you think of AMD vs CommonJS
=> AMD(Asynchronous Module Definition)와 CommonJs는 둘다 자바스크립트에서 모듈을 선언하는 방법에 대한 명세 입니다.
CommonJS는 동기로 동작을 하고 (비동기로 사용을 할 수도 있습니다) 서버 에서 자주 사용합니다. node에서 체택하였습니다.
javascript를 브라우저가 아닌 곳에서도 사용해보자는 취지에서 등장하였습니다.
필요한 파일이 모두 로컬 디스크에 있어 바로 불러 쓸수 있는 서버사이드와 같은 상황에서는 commonjs를 주로 사용합니다.
네트워크를 통해 받아와야 하는 브라우저 상황에서는 좀 더 유연한 처리가 필요했습니다. 그래서 commonjs에서 독립되어서 나온것이 AMD(Asynchronous Module Definition)입니다.
AMD에서는 define 함수를 통해 파일단위의 스코프를 제공해 줍니다.
AMD는 비동기로 동작을 하고 브라우저의 비동기 처리를 다루기 위해 commonJS에서 파생되었습니다. 대표적으로 requirejs가 있습니다.
브라우저에서는 es2015 모듈을 자주 사용하지만 Es2015모듈은 IE와 같은 특정브라우저에서는 동작하지 않아 babel과 같은 transpiler를 이용하여 commonJs로 컴파일 하여 사용합니다.
기존의 모듈을 사용하지 않고 script로 일일히 불러오게 되면 전역변수의 관리등 애로사항이 많게 됩니다.
따라서 모듈 시스템이 등장하게 되었습니다.
모듈 시스템은 객체 단위의 스코프를 가지게 됩니다.
Explain Why the following doesn't work as an IIFE: function foo(){}(); What needs to be changed to properly make it an IIFE??
=> 자바스크립트 엔진에서 function foo(){} 은 함수 선언식으로 인식이 되고 파싱이 됩니다.
()만 남게되어 에러가 발생하게 됩니다.
IIFE(Immediately Invoked Function Expression) 으로서 사용을 하기 위해서는 ()로 전체를 감싸주거나 함수 선언식을 감싸주어 함수 표현식으로 변경해 주어야 합니다.
즉시 실행 함수에서는 기명함수로도 익명함수로도 동작할 수 있습니다.
즉시 실행 함수를 사용하는 이유는 전역변수에 불필요한 변수를 추가하지 않기 위해 사용합니다.
맨처음 시작시 변수들을 초기화 하거나 와 같을때 사용하곤 합니다
(function(){})() // undefined
(function(){}()) // undefined
(function foo(){})() // undefined
(function foo(){}()) // undefined
What's the difference between a variable that is:null,undefined or undeclared?
How would you go about checking for any of these states?
null은 변수를 선언을 한후에 빈 값으로 처리된 상태입니다.
undefined는 선언은 되었고 초기화까지 된 상태 입니다.
undeclared는 선언조차 되지 않았다는 것을 의미합니다.
자바스크립트 엔진은 변수를 해석할때 세개의 단계를 거칩니다.
1. 선언
2. 초기화
3. 할당
선언은 변수로 선언할 대상들을 목록화 한것으로 알고 있습니다.
초기화는 변수에 물리적인 메모리 공간을 할당하는 것인데 이때 undefined를 통해 아직 실제 값이 할당되지 않았다는 것을 나타냅니다.
할당은 변수에 실제 값을 할당해주는 것입니다.
// 선언, 초기화
var foo;
console.log(foo) // undefined
// 할당
foo = 3;
console.log(foo) // 3
아래의 코드로 세개의 상황을 체크 하는 것을 확인할 수 있습니다.
console.log(x)
// x 변수는 선언된 적이 없으므로 referenceError가 출력되게 됩니다.
var foo;
console.log(foo); // undefined
console.log(foo === undefined) // true
console.log(typeof foo === 'undefined') // true
var foo = null
console.log(foo === null) // true
console.log(typeof foo === 'object') // true
// 주의해야할점
console.log(undefined == null) // true
console.log(undefined === null) // false
== 비교연산자를 사용하게 되면 undefined == null은 true를 리턴합니다.
undefined과 null을 비교해야할시 정확한 결과를 얻고 싶다면 === 를 사용해야 합니다.
==는 타입을 친절히 변환해주어서 결과를 리턴해주기 때문에 ===를 통해 타입과 값까지 비교해줄수 있도록 해야합니다.
console.log(0 == []) // true
console.log(0 === []) // false
What is a closure, and how/why would you use one?
클로저는 이미 생명주기가 끝난 함수의 변수를 참조하는 것입니다.
스코프체인 참조되는 변수 객체가 계속 남아있어서 가비지 컬렉터에 의해 제거되지 않습니다.
아래는 코드로 클로저를 구현한 예시 입니다.
function outerFunc() {
var count = 0;
function innerFunc() {
count += 1;
console.log(count);
}
return innerFunc
}
var innerFunc = outerFunc() // outerFunc의 실행 컨텍스트는 종료
innerFunc() // 1
innerFunc() // 2
클로저는 주로 private한 변수를 사용하고자 할때 사용합니다.
외부에서 해당 변수에 접근을 할 수가 없기 때문에 private의 성격을 띌수 있습니다.
Can you describe the main difference between a.forEach loop and a.map() loop and why you would pick one versus the other?
map과 forEach의 차이점은 새로운 배열을 return 해주는 것에 있습니다.
forEach는 단순히 배열을 순회하고자 할때
map은 원래의 값을 변화시키지 않으면서 새로운 배열을 얻고자 할때 사용합니다.
forEach
아래의 코드와 같이 value와 index를 통해 값을 체크하고 배열을 순회할 수 있습니다.
const test = [1,2,3,4,5]
test.forEach((value, index) => { // 액션 실행 })
map
아래의 코드와 같이 새로운 부수 배열을 만들어 낼수 있습니다.
test 배열의 변화 없이 새로운 배열을 뽑아낼 수 있습니다.
const test = [1,2,3,4,5]
const testArray = test.map((el, index) => el % 2 === 0 ? el : 0)
console.log(testArray) // [0, 2, 0, 4, 0]
What's a typical use case for anonymous functions?
익명함수를 사용하는 경우는 크게 3가지 입니다.
1. 즉시 실행 함수
2. 콜백함수
3. 함수형 프로그래밍
1. 즉시 실행 함수
=> 즉시 실행 함수 에서는 익명함수를 사용할 수 있습니다. 물론 기명함수 또한 사용할 수 있습니다.
즉시 실행 함수를 사용함으로써 전역범위의 스코프를 오염시키지 않으면서 원하는 동작을 수행할 수 있습니다.
(function () {})()
2. 콜백 함수
=> 콜백함수로서 사용합니다.
콜백함수는 호출될때만 실행되고 다른곳에선 쓰이지 않는다는 특성이 있습니다.
콜백함수에 전역으로 생성된 함수를 전달할 수도 있지만 아래와 같이 익명함수를 넣어줌으로써 전역 범위에 함수를 생성하지 않고 원하는 동작을 수행할 수 있습니다.
아래의 코드에는 기명함수를 넣어주어도 동작합니다.
setTimeout(function(){
console.log(this)
}, 1000)
3. 함수형 프로그래밍
함수형 프로그래밍을 사용하기 위해 익명함수를 사용합니다.
함수형 프로그래밍의 작성에 있어 필요한 순수함수를 작성하는데 이용할 수 있습니다.
const numbers = [1,2,3,4,5]
const even = numbers.filter(function(el) { if(el % 2 === 0) { return el} })
console.log(even); // [2,4]
함수형 프로그래밍이란 기존의 명령형 프로그래밍이 아닌 선언형 프로그래밍에 집중하는 것입니다.
명령형 프로그래밍이 어떻게 하는 것에 focusing을 두고 있다면
함수형 프로그래밍은 무엇을 하는 것에 focusing을 두고 있습니다.
순수함수란 동일한 입력값에는 같은 결과값을 호출하여 주고 외부의 인자를 참조하지 않는 것입니다.
const add = function(num1, num2){ return num1 + num2 }
add(1,2) // 3
add(2,3) // 5
함수형 프로그래밍과 순수함수에 관하여는 따로 상세히 포스팅 할 수 있도록 하겠습니다.
How do you organize your code? (module pattern, classical inheritance?)
프론트는 주로 React를 사용하며 모듈패턴을 항상 사용합니다.
백엔드를 구성할때 rails와 javascript로 구성할때가 있는데 이때는 상속패턴을 기반으로 Module을 적용하여 사용합니다.
rails 에서는 주로 모델에서 include를 통해 모듈들을 불러와 사용하고
javascript에서는 es6 방식을 이용하여 모듈을 불러옵니다.
javascript에서 nestjs를 사용할때는 모델의 속성을 정의해야 할때가 있습니다.
이때 created_at, updated_at, deleted_at과 같은 공통된 속성들을 가지는 클래스를 생성해 둡니다.
이후 새로 모델을 추가할때마다 이 클래스를 extends 해주어 반복되는 코드량을 줄입니다.
cli 도구를 만들어야 했을때는 추상클래스를 이용해 클래스들이 수행해야 하는 메소드를 정의해 두었습니다.
이 추상클래스를 생성해두고 비슷한 역할을 해야하는 클래스들에서 implements를 이용해 상속을 받았습니다.
이렇게 하고 개별 클래스에서 메소드를 override해주었습니다.
새로 생성되는 클래스들의 메소드를 통일할 수 있었고 코드의 파악이 쉬워졌던 경험이 있습니다.
What's the difference between host objects and native objects?
네이티브 객체는 Ecma 스크립트에 정의된 객체를 말합니다.
네이티브 객체는 어플리케이션의 환경과 상관없이 사용이 가능합니다.
Number, Boolean, String, Function, Array, RegExp 등과 같은 것들이 있습니다.
호스트 객체는 런타임 환경에서 제공해주는 객체를 의미합니다.
window, XMLHTTPRequest, HTMLElement등의 DOM 노드 객체와 같은 호스트 환경에 정의된 객체들을 뜻합니다.
Difference between:function Person(){}, var person = Person(), and var person = new Person()?
function Person() {}
함수를 선언 하는 것입니다. 함수 선언식으로 불리기도 합니다.
호이스팅이 발생하며 전역범위에 함수가 등록됩니다.
함수의 스코프는 선언되는 위치에 따라 결정됩니다.(this의 값은 호출되는 위치에 따라 달라집니다.)
Person()으로 호출할 수 있습니다.
var person = Person()
함수 표현식을 나타내려고 한건지 결과값만 저장하려고 한건지 Person에서 내부함수를 리턴해주는 것인지 모르겠습니다.
함수 표현식으로 사용하면 var의 person값만 호이스팅이 되게 됩니다.
선언과 초기화는 이루어지고 할당은 나중에 됩니다.
Person에서 내부함수를 리턴해준다면 함수 표현식이 될수도 있고 이러한 경우 클로저의 개념을 사용할 수도 있습니다.
var person = new Person()
함수를 생성자 함수로서 호출하는 것입니다.
새로운 인스턴스를 생성해냅니다.
이때 생성자 함수내부의 this는 생성되는 객체를 가리키게 됩니다.
생성자 함수를 호출할 때 인자를 같이 넣어주고 this.name 과 같이 property를 연결해주곤 합니다.
What's the difference between .call and .apply?
.call과 .apply는 this를 바인딩 할때 사용합니다.
call은 함수의 인자를 하나씩 순서대로 넘겨주며
apply는 함수의 인자를 배열로 넘길수 있다는 차이점이 있습니다.
var foo = function(a, b){
console.log(this.name);
console.log(a);
console.log(b);
}
var name = 'window'
var obj = {
name: 'test'
}
foo(1,2) // window, 1, 2
foo.call(obj, 1, 2) // 'test', 1, 2
foo.apply(obj, [1,2]) // 'test', 1, 2
ExplainFunction.prototype.bind
bind 메소드는 함수내의 this를 같이 넘겨준 인자로 할당해 줍니다.
리턴값은 this가 바인딩된 메소드를 리턴해 줍니다.
따라서 리턴후 즉시 실행을 시켜주려면 ()문을 추가해주어야 합니다.
()안에 인자를 넣어주면 함수에 인자를 넘기는것과 같습니다.
var foo = function(a, b){
console.log(this.name);
console.log(a);
console.log(b);
}
var name = 'window'
var obj = {
name: 'test'
}
foo.bind(obj) // undefined
foo.bind(obj)() // test, undefined, undefined
foo.bind(obj)(1,2) // test, 1, 2
When would you use document.write()?
document.write는 IE에 대한 호환성 문제나 스크립트의 병렬적인 로딩, 분석코드의 실행이 필요할때 사용합니다.
저는 사용해본 적이 없습니다.
document.write를 실행하면 document.open을 통해 새창이 열리고 인자로 받은 내용들이 컨텐츠로 보이게 됩니다.
<script> 태그로 감싼후 사용하게 되면 파라미터 인자만 화면에 출력하게 해줍니다.
함수의 실행으로 실행하게 되면 새창이 열리게 됩니다.
What's the difference between feature detection, feature inference, and using the UA string?
feature detection은 기능이 실제로 있는지 프로그래밍 적으로 테스트하여 사용하는 기술입니다.
아래 코드는 런타임 환경에서 navigator에 geolocation이 있으면 a 없으면 b를 수행하게 할 수 있습니다.
if ('geolocation' in navigator) {
// do a
} else {
// do b
}
위의 코드는 여러 브라우저의 오래된 버전에서 b를 수행하게 될 것입니다.
feature inference는 용어 그대로 기능 추론입니다.
만약 a가 b를 가진다면 당연히 c도 가지고 있겠지와 같은 방식입니다.
if (document.getElementsByName) {
element = document.getElementById(id);
}
ua 문자열은 요청한 브라우저가 어느 브라우저에서 요청했는지에 대한 정보를 가지고 있습니다.
핸드폰인지 tablet인지 또한 알수 있고 브라우저의 종류또한 알수 있습니다.
이 ua 문자열을 통해 안드로이드 폰에서는 애플로그인이 노출 안되게 할 수도 있고 인터넷 익스플로러를 지원하지 않는 서비스라면 지원하지 않는 서비스라는 정보를 띄워줄 수도 있습니다.
navigator객체의 userAgent 메소드로 정보를 가져올 수 있습니다.
Explain Ajax in as much detail as possible.
Ajax(Asynchronous javascript and Xml)는 javascript를 이용하여 서버와 비동기적으로 통신하기 위한 웹 개발 기술입니다.
ajax를 이용하면 전체 페이지의 로드 없이 요청을 보낸 후에 응답으로 원하는 페이지의 일부분만 받아온 데이터로 보여줄 수 있습니다.
XMLHttpRequest 객체를 이용하면 서버에 요청을 보낼수 있습니다.
jquery에서 또한 가능하고
fetch 함수를 이용하면 쉽게 handling 할수 있습니다.
axios와 같은 라이브러리를 이용하는 것도 좋은 방법입니다.
What are the advantages and disadvantages of using Ajax?
ajax를 이용하면
전체 페이지의 변경없이 필요한 부분만 최신화된 정보를 보여줄 수 있습니다.
이를 통해서 웹페이지의 속도를 향상시키고, 페이지 새로고침 없이 변경된 정보를 보여줄 수 있습니다.
단점은
브라우저에서 javascript 동작이 불가능하면 동작하지 않습니다.
서버요청이 더 많아질 수 있습니다.
하나의 요청이 실패하게 되면 전체 페이지에 문제가 생길수도 있습니다.
Explain how JSONP(JSON with Padding) works (and how it's not really Ajax).
jsonp는 다른 도메인의 서버로부터 데이터를 요청하기 위해 사용됩니다. (동일출처 정책을 우회하기 위한 꼼수로 이해했습니다.)
get 방식만 가능합니다.
웹 브라우저에서 실행되는 자바스크립트는 동일 출처 정책으로 인해 스크립트 태그 내에서 XMLHttpRequest 등으로 다른 도메인의 정보를 받아오는 것이 불가능 합니다.(요청은 가지만 브라우저단에서 해당 요청을 block 시킵니다)
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', 'http://server.example.com/Users/1234', true);
xmlhttp.onload = function () {
console.log('Retrieved Data: ' + xmlhttp.responseText);
};
xmlhttp.send(); // -> 교차 출처 요청 차단
위의 코드는 앞서 언급한 것과 같이 동일 출처 정책에 따라 오류가 발생합니다.
이는 아래와 같이 변경하면 원하는 대로 사용할 수 있습니다.
<script type="application/javascript"
src="http://server.example.com/Users/1234?callback=parseResponse">
</script>
parseResponse를 빼게 되면 에러가 발생합니다.
웹 브라우저의 javascript 엔진이 변수, 상수 정의등의 특정한 상황 없이 나오는 중괄호 문법을 block으로 해석하기 때문입니다.
외부 서비스 server.example.com은 JSON 데이터를 패딩하여 클라이언트에 보냅니다.
parseResponse({"Name": "Foo", "Id": 1234, "Rank": 7});
브라우저에서는 이 응답을 사용할 수 있게 됩니다.
JSONP를 직접 사용해본적은 없고 CORS로 대체되고 있는 것으로 알고 있습니다.
Have you ever used JavaScript templating? If so, what libraries have you used?
script에 type 속성에 text/template을 주어 html에 위치 시킨뒤에 document.querySelector를 이용하여 template을 가져온 후
원하는 내용을 replace해주어 화면에 나타낸적이 있습니다.
라이브러리는 handlerbar, template7, jsx에서 사용해 본 적이 있습니다.
es6가 나온이후에는 template literal을 활용하여 원하는 데이터를 나타낼 수도 있습니다.
Explain "hoisting".
javascript에서 var, let, const, function, class 등 모든 선언자는 자바스크립트 엔진에 의해 자신의 스코프 내에서 최상단으로 끌어올려 집니다.
var는 함수 스코프, let, const는 블록 스코프 입니다.
let,const는 호이스팅이 되면 TDZ(Temperal Dead Zone)에 위치하게 됩니다.
값을 할당하기 전에는 사용이 불가능 합니다.
const는 변수를 선언시 할당또한 같이 해주어야 하며
let은 선언후에 나중에 할당해줄수 있습니다.
위의 이미지는 var가 호이스팅 되었다는 것을 보여줍니다.
위의 코드에서 people이 호이스팅이 되면
아래와 같이 코드가 구성되게 됩니다.
var people;
console.log(people) // undefined
people = "rick"
console.log(people) // rick
함수 선언식 또한 호이스팅 됩니다.
아래의 함수 sum은 호이스팅이 됩니다.
console.log(sum(1,2)) // 3
function sum(a,b) {
return a + b;
}
console.log(sum(2,3)) // 5
아래는 호이스팅 된 함수 입니다.
function sum(a,b) {
return a + b;
}
console.log(sum(1,2))
console.log(sum(2,3))
그래서 함수 표현식을 권고합니다.
console.log(sum(1,2)) // error occured => sum is not a function
var sum = function (a,b) {
return a + b;
}
console.log(sum(2,3))
var로 선언된 sum은 호이스팅이 되지만 변수에 할당은 나중에 됩니다.
그래서 함수표현식으로 사용하는 경우
코드의 하단에서 상위에 정의되어 있는 함수들을 override하지 않을수 있습니다.
아래는 const로 선언한 변수 또한 호이스팅 되는 예시 입니다.
만약에 호이스팅이 되지 않았다면 foo는 스코프 체인에 따라 상위 스코프의 foo에 할당된 3을 출력해야 할것입니다.
const foo = 3
{
console.log(foo) // cannot access 'foo' before initialization
const foo = 3;
}
Describe event bubbling.
dom 요소에서 이벤트가 발생하면 해당 이벤트는 상위의 요소들로 계속 전달되어 집니다.
이 전달은 최상위 요소인 body 태그까지 전달됩니다.
dom 요소에서 이벤트(click과 같은)가 발생하고 만약에 이벤트 핸들러가 해당 요소에 있다면 이벤트를 핸들링 합니다.
<body>
<div class="one">
<div class="two">
<div class="three"></div>
</div>
</div>
</body>
var divs = document.querySelectorAll("div")
divs.forEach((div) => {
div.addEventListener('click', test)
})
function test(event) {
console.log(event.currentTarget.classList);
}
와 같이 작성한후 three를 클릭하게 되면
three, two, one 을 차례대로 출력하게 될것입니다.
What's the difference between an "attribute" and a "property"?
attribute 속성은 html markup에 정의되는 값이고 property는 dom 객체에서 사용됩니다.
위의 image들 처럼 input에 html markup attribute로 value를 추가해주었습니다.
attribute로 가져온 value값과 input의 현재 value 값을 가져오면 다르게 나타납니다.
attibute는 html에 정의되어있고
property는 dom객체에서 사용되기 때문입니다.
attribute는 대문자로 선언을 해도 소문자로 추가되고 값도 문자열만 가능합니다.
property는 대소문자를 식별하며 모든타입의 값이 들어갈수 있습니다.
Why is extending built-in JavaScript objects not a good idea?
built-in javascript 객체를 확장시킨다는 것은 해당 객체를 prototype으로서 사용하는 모든 객체에 영향을 줄수 있습니다.
이것의 의미는 확장된 기능의 적용 범위가 내가 의도한 범위가 아닌 범위에도 적용될 수 있다는 것입니다.
그 범위는 기존에 작성되어 있는 코드일수도 있고 새로 추가되는 코드일 수도 있습니다.
만약 실수로 이미 사용되고 있는 함수를 override 하게 된다면 기존에 동작중인 코드에도 영향을 끼칠수 있어 기능 자체에 문제가 생길수 있습니다.
이러한 위험성 때문에 내장 객체는 함부로 확장하지 않는게 좋은것 같습니다.
Difference between document load event and document DOMContentLoaded event?
load 이벤트는 dom트리가 그려진 후 필요한 Resource(이미지, stylesheet, script 파일)들이 전부 로드가 끝난후에 이벤트가 발생하게 됩니다.
DOMContentLoaded 이벤트는 dom 트리가 그려진 후 바로 이벤트가 발생합니다. resource들이 다운로드 되기를 기다리지 않습니다.
resource들을 로드하는데 시간이 필요하다면 DOMContentLoaded 이벤트를 사용하여 reource들의 로드를 기다릴 필요없이 이벤트를 발생 시킬수 있습니다.
What is the difference between == and ===?
==는 es6 이전에 비교 연산자로 사용하던 것으로 타입이 다르다면 타입을 변화한후에 값이 같은지를 반환해 줍니다.
===는 es6에 등장한 비교 연산자로 타입까지 비교해주어 유용하게 쓰입니다.
아래는 그 예시 입니다.
1 == '1' // true
1 == true // true
1 == [1] // true
null == undefined // true
1 === '1' // false
1 === true // false
1 === [1] // false
null === undefined // false
==는 사용하지 않는 것을 선호합니다.
Explain the same-origin policy with regards to JavaScript.
동일 출처 정책은 어떤 출처에서 가져온 문서 혹은 스크립트에서 다른 출처에서 가져온 리소스와의 상호작용을 제안 합니다.
이때 출처는 프로토콜, 포트, 호스트가 같아야 합니다.
이를 통해 공격받을 수 있는 경로를 줄여줍니다.
ex) http://dkrnfls.tistory.com/dir2/example.html => 성공
https://dkrnfls.tistory.com/dir2/example.html => 실패 (프로토콜이 다름)
https://www.naver.com/dir2/example.html => 실패 (호스트가 다름)
http://dkrnfls.tistory.com:81/dir2 => 실패 (포트가 다름)
쉬운말로 javascript에서 ajax 요청을 보낼때 현재 요청을 보내는 도메인과 다른 도메인에서 응답이 오는 경우 이를 브라우저에서 제한 합합니다.
이걸 해결할 수 있는 것이 cors(cross origin resource sharing) 입니다.
서버에서 응답을 보내줄때 Access-Control-Allow-Origin 헤더에 클라이언트의 도메인을 추가해주거나 wildcard를 추가해주어 교차출처 접근을 허용해줄수 있습니다.
일반적인 요청들은 cors에 상관없이 요청과 응답이 가능합니다.
그러나 이러한 일반적인 요청은 아래의 모든 조건을 충족시켜야 합니다.
* get, post, head 중 하나의 메서드
* 헤더에 사용할 수 있는 값은 아래의 속성 뿐
* accept
* accept-language
* content-language
* content-type
* content-type에는 아래의 값들만 허용됩니다.
* application/x-www-form-urlencoded, multipart/form-data, text/plain
=> 우리는 json 요청을 주로 보내기 때문에 위의 일반적인 경우에는 해당할 수가 없습니다...
서버에서 받는 요청의 헤더에 origin을 통해 어느 클라이언트에서 왔는지 확인이 가능합니다.
아래는 클라이언트의 요청
GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
아래는 서버의 응답
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
[…XML Data…]
cross-origin 요청은 유저 데이터에 영향을 줄 수 있으므로 preflight 요청을 보냅니다.
이때 options 메서드를 이용합니다.
미리 안전한지 확인해 본다고 저는 이해하고 있습니다.
아래의 이미지를 보면 xhr 요청 전에 같은 경로로 preflight 요청을 보낸것을 확인할 수 있습니다.
Make this work:duplicate([1,2,3,4,5]); // [1,2,3,4,5,1,2,3,4,5]
function duplicate(arr) {
return arr.concat([...arr])
}
console.log(duplicate([1,2,3,4,5]))
function duplicate(arr) {
return [...arr, ...arr]
}
console.log(duplicate([1,2,3,4,5]))
function duplicate(arr) {
return arr.concat(arr)
}
console.log(duplicate([1,2,3,4,5]))
Why is it called a Ternary expression, what does the word "Ternary" indicate?
삼항연산자를 의미합니다.
javascript 에서는 if else 를 ? 로 간단하게 사용할 수 있습니다.
var flag = true
console.log(flag ? "yes" : "no")
What is "use strict";? what are the advantages and disadvantages to using it?
use strict 모드는 말 그대로 엄격한 모드 입니다.
평소에는 에러로 반환하지 않던 것들을 use strict 에서는 에러로 반환해 줍니다.
장점
* 전역 변수가 의도치 않게 생기는 것을 방지해 줍니다.
'use strict'
// 전역변수 mistypedVariable가 존재한다고 가정
mistypedVaraible = 17; // 오타로 인해 ReferenceError 발생시킴
* 기존에는 조용히 무시되던 에러들을 throwing 합니다
"use strict"
// 쓸 수 없는 프로퍼티에 할당
var undefined = 5; // TypeError 발생
var Infinity = 5; // TypeError 발생
// 쓸 수 없는 프로퍼티에 할당
var obj1 = {};
Object.defineProperty(obj1, 'x', { value: 42, writable: false });
obj1.x = 9 // TypeError 발생
// getter-only 프로퍼티에 할당
var obj2 = { get x() {return 17;} }
obj2.x = 5 // TypeError 발생
// 확장 불가 객체에 새 프로퍼티 할당
var fixed = {}
Object.preventExtensions(fixed);
fixed.newProp = "ohaio" // TypeError 발생
* 삭제할 수 없는 프로퍼티를 삭제하려 할때 error를 반환합니다.
"use strict"
delete Object.prototype // 에러 발생
* 전역 this는 use strict에서 undefined로 반환 됩니다.
단점
* 일부 개발자는 익숙하지 않은 기능이 있을수도 있습니다.
* 서로 다른 엄격한 모드로 작성된 스크립트를 병합하면 문제가 발생할 수 있습니다.
es6 에서는 strict mode가 default 이기 때문에 따로 선언해줄 필요가 없습니다.
모듈에도 자동적으로 strict mode가 적용됩니다.
Create a for loop that iterates up to 100 while outputting "fizz" at multiples of 3, "buzz" at multiples of 5 and "fizzbuzz" at multiples of 3 and 5
for (let i = 1; i< 100; i++) {
if (i % 3 === 0 && i % 5 === 0){
console.log('fizzbuzz')
}
else if(i % 3 === 0) {
console.log('fizz')
}
else if(i % 5 === 0) {
console.log('buzz')
}
}
Why is it, in general, a good idea to leave the global scope of a website as-is and never touch it?
전역범위에 사용을 하게 되면 모든 범위에서 접근할 수 있다는 장점이 있지만 반대로 모든 범위에서 접근할 수 있다는 단점이 있습니다.
상위에 선언된 전역변수를 스크립트의 하단에서 override 하게 된다면 전역변수의 충돌이 일어날 수 있습니다.
함수 선언식으로 선언된 경우 기존에 해당 함수를 사용하던 곳 또한 영향을 받게 됩니다.
따라서 모듈화를 적용하여야 합니다. 클로저나 즉시 실행함수를 이용하거나 파일들을 모듈들로 쪼개어 사용하여야 합니다.
es6의 모듈 방식을 주로 사용합니다.
node에서는 commonjs 방식을 모듈에 적용 하고 있습니다.
Why would you use something like the load event? Does this event have disadvantages? Do you know any alternatives, and why would you use those?
load 이벤트는 dom tree와 문서에 필요한 리소스들(script, image)들이 전부 다운로드 되고 나서 스크립트를 실행합니다.
스크립트 내에서 조작해야 하는 것들이 다운로드된후 존재할때 사용합니다(이미지의 사이즈 등등)
대안으로 DOMContentLoaded 메소드가 있습니다.
DOMContentLoaded 메소드는 DOM tree가 그려지고 나서 바로 스크립트를 실행시킬수 있습니다.
모든 이미지 혹은 스크립트들의 다운로드에는 시간이 오래 소요될 수도 있으므로 이들을 다운로드 하기 전에 스크립트를 실행시킬 수 있습니다.
Explain what a single page app is and how to make one SEO-friendly.
SPA(single page app)은 최초 요청시에는 html을 응답받고 이후의 요청은 ajax를 통해 필요한 데이터만 Json 형식으로 전달 받습니다.
필요한 데이터만 서버로부터 전달받으므로 트래픽을 줄일 수 있고 사용자에게 더 빠른 응답속도를 보일수 있습니다.
라우팅에는 html5의 history api를 이용해 페이지가 이동하는 것처럼 보일수 있습니다.
History api에는 history.back(), history.forward(), history.pushState(), history.popState()와 같은 메소드들이 있습니다.
최초 렌더링은 느릴수 있습니다. html과 필요한 js를 모두 다운로드 받아야 하기 때문입니다.
하지만 이후의 페이지 이동이나 응답은 필요한 것들을 json으로 받아오기 때문에 상대적으로 빠릅니다.
seo에 좀 더 최적화 하려면 ssr 방식을 고려하여야 합니다.
spa에서는 js의 동작으로 사이트의 metadata가 변경되게 됩니다.
하지만 검색엔진의 크롤러 봇들은 js를 실행시키지 않습니다.(구글의 크롤러 봇은 js를 실행시키는 것으로 알고 있습니다)
따라서 seo를 위해서는 서버에서 즉시 렌더가능한 html 파일을 보내주는 ssr 방식을 고려하여야 합니다.
What is the extent of your experience with Promises and/or their polyfills?
api를 병렬적으로 동시에 이용하고 모든 요청이 성공했을때 처리를 위해 Promise.all을 사용해 본적이 있습니다.
Promise.all에는 promise객체가 배열의 인자로 들어가게 됩니다.
Promise.allSetteled 는 promise의 상태를 반환합니다.
pending, fulfilled, rejected와 value를 반환합니다.
Promise는 비동기 작업을 처리하기 위해 es6에서 등장하였습니다.
등장하기 이전에는 비동기 작업을 처리하기 위해 콜백을 이용하였습니다.
콜백이 여러개 쌓이면서 콜백 hell을 경험할 수도 있습니다.
es6 이전의 버전에서는 promise의 polyfill을 사용하여야 합니다.
polyfill은 보충하는 솜(보충재)이라는 뜻으로 웹 개발에서 기능을 지원하지 않는 웹 브라우저 상의 기능을 구현하는 코드를 의미합니다.
직접 구현하거나 babel의 polyfill을 이용하여 promise 기능을 지원하지 않는 브라우저에서도 promise의 기능이 동작하도록 할 수 있습니다.
import "@babel/polyfill";
What are the pros and cons of using Promises instead of callbacks?
장점
- callback 지옥을 피할 수 있습니다.
- then, catch, finally를 통해 연속된 흐름을 가독성 있게 작성할 수 있습니다
- Promise.all을 통해 여러개의 비동기 코드를 병렬적으로 실행할 수 있습니다.
- error처리 또한 가독성 있게 처리할 수 있게 됩니다.
단점
- es6를 지원하지 않는 브라우저에서는 polyfill이 필요합니다.
- 코드에 익숙치 않으면 복잡하게 느낄 수 있습니다.
let a = (cb) => setTimeout(cb, 1000)
let b = (cb) => setTimeout(cb, 1000);
let c = (cb) => setTimeout(cb, 1000);
let d = (cb) => setTimeout(cb, 1000);
let test = () => {
a(() => {
console.log('a');
b(() => {
console.log('b')
c(() => {
console.log('c');
d(() => {
console.log('d')
})
})
})
})
};
test();
위의 코드는 콜백과 setTimeout을 이용한 콜백 hell의 예시입니다.
아래의 코드는 위의 콜백 hell 예시를 promise를 이용하여 가독성 있게 나타낸 코드입니다.
let a = () =>
new Promise((resolve, reject) => setTimeout(() => resolve("a"), 1000));
let b = () =>
new Promise((resolve, reject) => setTimeout(() => resolve("b"), 1000));
let c = () =>
new Promise((resolve, reject) => setTimeout(() => resolve("c"), 1000));
let d = () =>
new Promise((resolve, reject) => setTimeout(() => resolve("d"), 1000));
a()
.then((data) => {
console.log(data);
return b();
})
.then((data) => {
console.log(data);
return c();
})
.then((data) => {
console.log(data);
return d();
})
.then((data) => {
console.log(data);
});
What are some of the advantages/disadvantages of writing JavaScript code in a language that compiles to JavaScript?
javascipt로 컴파일 되는 script는 typescript만 사용해보았습니다. coffeescript, purescript와 같은 것들이 있습니다.
장점
- 코드를 더 짧게 작성할 수 있습니다.(coffeescript의 경우)
- typescript를 이용하면 유지보수에 더 용이해집니다.(type check를 할 수 있어 컴파일 전에 오류를 체크할 수 있습니다.)
- javascript의 문제를 해결할 수 있습니다.(ide에서는 컴파일 전에 에러를 띄워줌으로써 런타임의 에러를 방지할 수 있습니다. 변수의 mistyping과 같은 것들)
단점
- 해당 스크립트 언어에 대한 학습이 추가로 필요하게 됩니다.
- javascript의 최신버전을 반영하지 않을 수도 있습니다.
- 빌드나 컴파일 하는 과정이 필요하게 됩니다. typescript 컴파일러와 같은 도구들이 필요할수 있습니다.
- IDE나 에디터에서 지원하지 않을 수도 있습니다.
What tools and techniques do you use debugging JavaScript code?
React에서는 react developer tools extension을 설치하여 사용하였습니다.
렌더링 될때마다 색깔을 표시해주는 기능을 유용하게 사용했었습니다.
React query를 사용했었을때는 react query의 dev tool을
redux를 사용할때는 redux devtools를 사용하여 어떤 데이터가 dispatch되는지를 확인했었습니다.
vanilla js를 사용할때는 console을 찍어서 변수의 값이나 동작을 확인했었습니다.
debugger를 입력하여 크롬의 개발자 도구에서 확인하기도 했었습니다.
node에서는 vscode의 debugger를 사용하여 개발의 편의성을 확보하기도 했었습니다.
코드에 breakpoint를 찍으면 vscode 내에서 동작을 javascript의 debugger와 같이 사용할 수 있습니다.
What language constructions do you use for iterating over object properties and array items?
objcet의 속성들을 iterating해야 할때는 Object.keys를 이용하였습니다.
값만 순회하고 싶을때는 Object.values를
key,value를 차례로 알고싶을때는 Object.entries를 사용하였습니다
속성들만 순회하고 싶을때 for-in 문을 이용해서도 값을 가져올 수 있습니다
const testKeys = {a: '1', b: '2', c: '3'}
const keys = Object.keys(testKeys)
console.log(keys) // ['a', 'b', 'c']
const testValues = {...testKeys}
const values = Object.values(testValues)
console.log(values) // ['1', '2', '3']
const testEntries = {...testKeys}
const entries = Object.entries(testEntries)
console.log(entries) // [['a', '1'], ['b', '2'], ['c', '3']]
for (let key in testKeys) {
console.log(key) // a, b, c
}
배열을 순회할때는 for문을 이용하거나 forEach, map, filter 등을 이용하였습니다.
Explain the difference between mutable and immutable objects.
mutable object는 변경가능한 객체, immutable object는 변경이 불가능한 객체를 의미합니다.
함수형 프로그래밍에서 immutable object는 핵심 개념이라고 알고 있습니다.
javascript에서 원시 type의 객체들은 immutable한 객체들입니다.
var a = 'a'
var b = a;
b = 'b'
console.log(a) // 'a'
console.log(b) // 'b'
위와 같은 경우 b는 a의 값을 복제하여 새로운 메모리 주소에 할당합니다.
a의 값을 b로 인해 바뀌지 않습니다.
값에 의한 참조로 선언된 변수는 값이 변할수 있습니다.
let c = { a: 'a', b: 'b' }
let d = c
d.a = 'd'
c // {a: 'd', b: 'b'}
d // {a: 'd', b: 'b'}
javascript에서는 아래와 같은 메소드들로 immutable한 객체를 제공할 수 있습니다.
Object.defineProperty에서 writable 옵션을 false
Object.preventExtensions, Object.seal, Object.freeze
let a = {}
Object.defineProperty(a, 'b', {value: 42, writable: false, configurable: true });
a // {b: 42}
a.b = 43
a // {b: 42}
Object.preventExtensions(a)
a.c = 44
a // {b: 42}
a = { b: 'b' }
Object.seal(a)
a.c = 'c'
a // { b: 'b' }
a = { b: 'b' }
Object.freeze(a)
a.c = 'c'
a // { b: 'b' }
immutable한 객체를 사용함으로써
* 변화를 감지하기 쉽습니다(react에서 변수의 상태를 감시할때 사용하기 편리합니다.)
* 멀티 스레드 환경에서 값이 오염될 상황을 방지할 수 있습니다.
* 할당을 잘못하게 되면 매번 값이 생성되어 메모리를 비효율적으로 사용할 수도 있습니다.
Explain the difference between synchronous and asynchronous functions.
synchronous 함수와 asynchronous 함수는 동기, 비동기 함수를 각각 의미합니다.
동기 함수는 해당 함수의 실행이 끝날때까지 기다립니다.
하지만 비동기 함수는 해당 함수의 실행이 끝날때까지 기다리지 않습니다.
웹 api를 이용하거나 setTimeout과 같은 함수를 실행하면 함수들은 task queue에 push 됩니다.
이후 call stack이 비게되면 event loop에 의해 하나씩 콜 스택으로 이동하여 실행되게 됩니다.
api 요청을 하거나 많은 시간이 필요한 함수의 실행을 동기적으로 실행했을때 main thread에서는 해당 함수의 실행이 끝나기까지 기다려야 하므로 ui를 그리지 못하거나 하게 됩니다. 따라서 비동기 적으로 실행하는 것이 좋습니다.
https://html.spec.whatwg.org/multipage/webappapis.html#task-queue
What is event loop? What is the difference between call stack and task queue?
이벤트 루프는 call stack과 task queue를 계속 확인하면서 call stack이 비게 되면
task queue에서 꺼내와 call stack에서 실행할 수 있게 해줍니다.
call stack은 자바스크립트 엔진에 위치합니다. memory heap또한 같이 구성되어 있습니다.
함수의 실행이 호출되면 콜스택에 push 되고 하나씩 실행되게 됩니다.
web api와 task queue는 html에서 제공됩니다.
html은 마크업 언어 뿐만 아니라 많은 api들을 의미합니다.
fetch, setTimeout, setInterval 등등 web api가 호출되면 (만약 timer가 있다면 timer수행후에) task queue에 하나씩 넣어줍니다.
이후 event loop가 call stack과 task queue를 주기적으로 확인하여 call stack이 비게되면 queue에서 하나씩 꺼내와 실행하게 해줍니다.
Explain the differences on the usage of foo between function foo() {} and var foo = function() {}
function foo() {} 는 함수 선언식 입니다. 이러한 형태로 사용하게 되면 함수 전체가 호이스팅이 일어나게 됩니다.
var foo = function(){} 는 함수 표현식 입니다. 이 형태는 foo 변수만 호이스팅이 일어나게 됩니다.
함수 선언식으로 사용하게 될 경우 오버라이딩이 일어날 수 있게 됩니다.
상위에서 function sum 으로 정의하여 사용하고 있는 경우 아래에서 function sum으로 override하게 되면
이미 선언한 sum을 이용하고 있던 코드도 영향을 받게 됩니다.
function sum(a, b){
return a + b;
}
sum(1,2) // 7
function sum(a,b) {
return a + b + 4;
}
sum(1,2) // 7
What are the differences between variables created using let, var or const?
let과 const는 블록 스코프, var는 함수 스코프를 가지게 됩니다.
또한 세가지 선언자를 이용해 선언한 변수들은 전부 호이스팅 됩니다.
다만 let과 const는 TDZ(Temperal Dead Zone)에 위치하게 되어 선언전에 사용하고자 하면 에러가 발생됩니다.
한가지 유의할 점은 const는 선언과 할당을 꼭 동시에 해주어야 합니다.
var 변수는 선언 전에 사용하더라도 undefined를 출력하게 됩니다.
함수 스코프와 블록 스코프를 확인하기 위한 코드는 아래와 같습니다.
{
let a = 'a'
}
console.log(a) // undefined
{
var b = 'b'
}
console.log(b) // 'b'
function test() {
var c = 'c'
}
console.log(c) // undefined
What are the differences between ES6 class and ES5 function constructors?
클래스는 프로토타입 기반 상속을 사용합니다.
같은 클래스를 재선언하게 되면 에러 발생합니다.
클래스 선언은 호이스팅이 되지 않습니다
function Person(name){
this.name = name;
}
class Person {
constructor(name) {
this.name = name;
}
}
아래 이미지는 class를 babel을 이용하여 es5로 나타낸 것입니다.
class를 이용하게 되면 생성자 함수의 prototype 성질이 writable: false가 되는것을 볼 수 있습니다.
가장 큰 차이는 상속에 있습니다.
학생이 사람을 상속받는 것을 가정해 보겠습니다.
class Person {
constructor(name){
this.name = name
}
}
class Student extends Person {
constructor(name, school) {
super(name)
this.school = school;
}
}
const student = new Student('홍길동', '동국')
console.log(student);
function Person(name) {
this.name = name;
}
function Student(name, school) {
Person.call(this, name);
this.school = school;
}
Student.prototype = Object.create(Person.prototype)
Student.prototype.constructor = Student
console.dir(Student)
const student = new Student('홍길동', '동국')
console.log(student);
class 문법을 이용하면 상속을 훨씬 편하게 사용할 수 있습니다. 이때 python과 같이 다중상속은 되지 않습니다.
Can you offer a use case for the new arrow => function syntax? How does this new syntax differ from other functions?
콜백함수 내부의 this가 외부 함수의 this와 다르기 때문에 발생하는 문제를 해결하기 위해 의도적으로 설계함
const sum = (a,b) => a + b;
console.log(sum(1,2)) // 3
화살표 함수는 위와 같이 사용합니다.
화살표 함수는 this를 가지지 않습니다. 그래서 콜백함수, 비동기적인 함수의 실행, 메소드에서의 사용에서는 this가 상위 스코프의 this를 가리킵니다.
함수의 스코프는 선언되는 위치에 따라 설정됩니다. 이를 렉시컬 스코프 혹은 정적스코프 라고 합니다.
화살표 함수는 생성자 함수로 사용할수 없습니다. prototype 속성을 가지고 있지 않기 때문입니다.
What advantage is there for using the arrow syntax for a method in a constructor?
생성자 함수에서 mehtod에 화살표 함수를 사용하게 되면 this는 생성된 객체를 가리키지 않습니다.
화살표 함수가 생성된 상위 스코프의 this를 가리키게 됩니다.
클래스형 컴포너트를 사용하는 리액트에서 생성자의 메소드에 화살표 함수를 사용하면 좋다는데 해당 예시는 잘 모르겠습니다.
아래의 코드는 메소드에서 화살표 함수를 사용한 예시입니다.
const Person = function (firstName) {
this.firstName = firstName;
this.sayName1 = function () {
console.log(this.firstName);
};
this.sayName2 = () => {
console.log(this.firstName);
}
}
const john = new Person('John')
john.sayName1(); // John
john.sayName2(); // John
const dave = new Person('dave')
// The regular function can have its 'this' value changed, but the arrow function cannot
john.sayName1.call(dave); // Dave (because "this" is now the dave object)
john.sayName2.call(dave); // John
john.sayName1.apply(dave); // Dave (because 'this' is now the dave object)
john.sayName2.apply(dave); // John
john.sayName1.bind(dave)(); // Dave (because 'this' is now the dave object)
john.sayName2.bind(dave)(); // John
var sayNameFromWindow1 = john.sayName1;
sayNameFromWindow1(); // undefined (because 'this' is now the window object)
var sayNameFromWindow2 = john.sayName2;
sayNameFromWindow2(); // John
What is the definition of a higher-order function?
고차함수는 하나 이상의 함수를 인자로 받거나 함수를 결과값으로 반환하는 함수를 말합니다.
고차 함수는 일반적인 함수인데 함수를 인자로 받고 함수를 반환할 수 있는 추가적인 기능을 가진 것이라고 이해하시면 될 것 같습니다.
대표적인 예시로 map, filter, reduce 등이 있습니다.
이들은 원본데이터의 변형을 초래하지 않아서 순수함수에 자주쓰이고 순수함수는 함수형 프로그래밍에 쓰입니다.
const arr = [1, 2, 3, 4, 5];
const mulitplyTwo = arr.map((el) => el * 2); // [2, 4, 6, 8, 10]
const underThree = arr.filter((el) => el < 3); // [1, 2]
const totalSum = arr.reduce((prev, next) => prev + next, 0); // 15
console.log(mulitplyTwo, underThree, totalSum);
Can you give an example for destructuring an object or an array?
구조 분해 할당은 Es6 부터 가능합니다!
const arr = [1,2,3]
const [one, two, three] = arr
console.log(one, two, three) // 1, 2, 3
const test = { a: 'a', b: 'b', c: 'c' }
const { a, b, c } = test
console.log(a, b, c) // a, b, c
ES6 Template Literals offer a lot of flexibility in generating strings, can you give an example?
const students = ['a', 'b', 'c', 'd', 'e']
const getStudentTemplate = '<li>name: {name}</li>';
const studentBoard = document.querySelector("ul")
students.forEach((student) => {
studentBoard.insertAdjacentHtml("beforeend", getStudentTemplate.replace('{name}', student))
})
const students = ['a', 'b', 'c', 'd', 'e']
const getStudentTemplate = (name) => `<li>name: ${name}</li>`;
const studentBoard = document.querySelector("ul")
students.forEach((student) => {
studentBoard.insertAdjacentHtml("beforeend", getStudentTemplate(student))
})
template literal을 사용하면 생성되는 DOM node에 eventHandler를 달기 애매하다.
이럴때는 이벤트 위임을 이용하거나 template tag를 front에 적재해두고 사용할 것 같다.
Can you give an example of a curry function and why this syntax offers an advantage?
const sum = (x) => (y) => x + y
sum(2)(5) // 7
const addFive = sum(5)
addFive(2) // 7
const sum = (a,b) => a + b;
sum.length // 2 함수의 length는 받는 인자의 수
sum(2,5) // 7
커링 함수는 복수개의 파라미터를 받는 함수에서 파라미터를 누적시킬 수 있습니다
커링 함수는 함수의 확장성을 활용하기에 좋습니다.
또한 확장된 함수를 사용함으로써 중복된 인자를 피할 수 있습니다.
const add = (a) => (b, c) => a + b + c
const addFive = add(5)
addFive(1,2) // 8
addFive(2,3) // 10
addFive(3,4) // 12
add(1,2,5)
add(2,3,5)
add(3,4,5)
const addSix = add(6)
addSix(1,2) // 9
addSix(2,3) // 11
addSix(3,4) // 13
add(1,2,6) // 9
add(2,3,6) // 11
add(3,4,6) // 13
What are the benefits of using spread syntax and how is it different from rest syntax?
es6에서 등장한 스프레드 문법은 객체나 배열을 복사해야할때 편하게 사용할 수 있습니다.
이때 1 depth에서는 깊은 복사, 2 depth 부터는 얕은복사가 이루어지게 됩니다.
const putDookieInAnyArray = (arr) => [...arr, 'Dookie']
const result = putDookieInAnyArray(["i", "really", "don't"])
const person = {
name: "Todd",
age: 29,
}
const copyOfTodd = {...person}
rest syntax는 spread 문법과 반대처럼 느껴집니다.
rest syntax는 함수의 인자나 구조 분해 할당에서 활용할 수 있습니다.
객체나 배열로부터 데이터들을 꺼내오는데 전체를 꺼내오는 것이 아닌 일부만 꺼내올수 있는 것처럼 느껴집니다.
const addFiveToBunchOfNumbers = (...numbers) => numbers.map(x => x + 5);
const result = addFiveToBunchOfNumbers(4,5,6,7,8,9,10) // 9 10 11 12 13 14 15
const [a, b, ...rest] = [1,2,3,4] // a: 1, b: 2, rest: [3,4]
const {e, f, ...others} = {
e: 1,
f: 2,
g: 3,
h: 4,
} // e: 1, f: 2, others: { g: 3, h: 4 }
How can you share code between files?
es6의 모듈 방식을 사용합니다. 이후에는 babel을 통해 es5 문법으로 Transpiling한 후에 웹팩으로 번들하여 하나의 파일을 배포합니다.
저는 코드를 기능별로 구분 하여 위치시키는 것을 좋아합니다.
하지만 도메인에 따라 기능이 아닌 같은 주제에 따라 위치 시킬때도 있습니다.
Why you might want to create static class members?
공통된 기능을 하는 함수나 요소가 있을때 static 요소를 고려합니다.
static 속성이나 메소드는 인스턴스의 상태에 의존하지 않는 순수함수를 보통 할당하곤 합니다.
'Frontend > Javascript' 카테고리의 다른 글
Javascript script async vs defer (0) | 2022.03.03 |
---|---|
innerHTML, insertAdjacentHTML, textContent, innerText (0) | 2022.03.01 |
🔥 System Design Concepts that Helped Me Get Sr Frontend Offers From Amazon & LinkedIn (번역글) (0) | 2022.02.27 |
js + cypress (0) | 2022.02.23 |
Frontend Interview Cheatsheet (0) | 2022.02.15 |