1-1. var
var x = 1;
function foo() {
var x = 10;
bar();
}
function bar() {
console.log(x);
}
foo(); // ?
bar(); // ?
let x = 1;
function foo() {
let x = 10;
bar();
}
function bar() {
console.log(x);
}
foo(); // ?
bar(); // ?
종한님 답:
→ var, let (const도 동일) 모두 동일하게 foo, bar 에서 1 출력
→ JS는 렉시컬 스코프 (함수를 어디서 정의했는지에 따라 함수의 상위 스코프 결정)
따라서 bar 함수는 정의된 곳의 스코프를 따른다 (전역 변수)
전역변수 x = 1 이므로 bar 함수가 foo 함수 (전역보다 하위 스코프)에서 호출되더라도 1을 리턴한다
내 답:
출력값은 모두 1
위 두 코드의 함수들은 모두 전역 변수인 x를 참조하고 있다. 전역 변수의 스코프는 코드 전체에 해당합니다. 따라서 코드 전제의 어디서든지 전역변수 x를 참조할 수 있습니다.
foo함수 안의 지역변수 x의 스코프는 foo함수 몸체 내부에만 한정됩니다. 따라서 bar함수는 foo함수의 지역변수 x를 참조할 수 없습니다.
때문에 모든 출력값은 전역 변수 x의 값인 1이 됩니다.
ME
console.dir(함수이름1) // 함수이름1(x, y)
console.dir(식별자) // undefined
console.log(함수이름1(1, 3)) // 4
console.log(식별자(1, 3)) // 식별자 is not a function
// 함수 선언문
function 함수이름1(x, y){
return x + y;
}
//함수 표현식
var 식별자 = function 함수이름2(x, y) {
return x+y;
}
내 답:
자바스크립트 엔진은 런타임 이전에 모든 선언문을 먼저 실행시킵니다. 그럼 함수 선언문도 실행 되겠죠? 그럼 런타임 이전에 함수 객체가 먼저 생성되는 것입니다. 그리고 JS엔진은 참 센스있게도(?) 함수 이름과 동일한 이름의 식별자를 생성해 이 식별자에 함수 객체를 할당합니다. 이렇게 되면 런타임에는 이미 함수 객체 생성과 함수 이름과 동일한 시별자에 함수 객체 할당까지 완료된 상태가 되는 것이죠. 따라서 함수 선언문 이전에 함수를 참조할 수 있고 호출할 수도 있게 되는 것이고 이렇게 함수 호이스팅이 일어납니다.
함수 표현식은 변수에 함수 리터럴 문이 할당되는 것입니다. 따라서 함수 표현식은 함수 호이스팅이 아닌 변수 호이스팅이 일어납니다. 즉 변수를 선언하고 그 변수에 함수 리터럴을 할당하는 것이죠 변수 선언 또한 런타임 이전에 실행되고 이때 변수의 경우는 undefined로 초기화 됩니다. 즉 함수 표현식의 변수는 undefined로 초기화 되었다가 런타임에 함수 표현식이 변수에 할당될 때 평가되어 함수 객체가 됩니다. 그래서 함수 표현식으으로 함수를 정의하면 변수 호이스팅이 발생하는 입니다.
형빈님 답: 일반 객체는 호출 할 수 없지만 함수는 호출이 가능하다.
내 답:
(+ 덧붙여 설명하기)
자바스크립트의 함수는 일급 객체입니다. 여기서 일반 객체와 일급 객체에 차이점을 짚고 넘어가지 않을 수 없을 듯 합니다. 먼저 일급 객체란 무엇일까요?
일급객체(First-class Object)란 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 가리킨다. [위키백과]
MDN을 살펴볼까요?
'변수'수 처럼 취급 가능하다는 것은 어떤 의미일 까요? 일급 객체의 조건은 아래와 같습니다.
1. 무명의 리터럴로 생성할 수 있다. (즉 런타임에 생성이 가능하다.)
2. 변수나 자료구조(객체, 배열 등)에 저장할 수 있다.
3. 함수의 매개변수로 전달할 수 있다.
4. 함수의 반환값으로 사용할 수 있다.
즉 자바스크립트에서는 함수를 데이터(string, number, boolean, array, object)를 다루듯이 다룰 수 있다는 것입니다. 자바스크립트의 함수는 일반 객체에는 없는 위와같은 특징들을 가지고 있습니다.
function deepDive(){
var x = 1;
var x = 2;
console.log(x);
}
deepDive(); // 2
function deepDive2(){
let x = 1;
let x = 2;
console.log(x); //syntaxError
}
deepDive2();
형빈님 답: var키워드는 중복선언이 허용된다.
내 답: var키워드로 선언된 변수는 재할당과 중복 선언이 모두 가능합니다. 그러나 let키워드로 선언된 변수는 재할당은 가능하지면 중복선언은 불가합니다. 따라서 두번째 코드에서 SyntaxError가 안나오게 하려면 아래와 같이 코드를 수정하면 됩니다.
function deepDive2(){
let x = 1;
x = 2;
console.log(x);
}
deepDive2();
//ARR배열에서 2인 값을 찾아내는 함수를 각각 filter와 for를 이용하여 작성하였습니다.
const ARR = [1,2,3]
const filter1 = ARR.filter((item)=> item === 2)
const testFunc = () =>{
for(let i=0; i<ARR.length; i++){
if(ARR[i]===2) return ARR[i]
}
}
const filter2 = testFunc()
console.log(filter1 === filter2)
// 아래 결과는 여러분과 함께 의견 공유하고 싶은 문제
console.log(filter1 == filter2)
형석님 답:
filter의 경우 결과값으로 무조건 배열을 반환하게 된다.
따라서 첫번째 console은 [2] === 2 이므로 false
두번째 console의 경우 타입 비교 없이 [2] == 2를 하게되는데 자바스크립트가 임의로 [2]를 2로 판단하여 2 == 2를 비교하게 되어 true가 나오게된다
내 정리:
잘 알지 못했던 부분!
위 코드에서 filter1 과 filter2를 찍어보면 각각
이렇게 나온다. filter매서드의 반환값은 항상 배열이라는 것!(filter1)
그래서 console.log(filter1 === filter2)
의 값은 false
가 된다.
반면 console.log(filter1 == filter2)
에서 ==
연산자의 경우 두 피연산자 값의 타입이 다를 경우 임의로 타입 변환을 한 후에 값을 비교한다. 즉 타입을 비교하지 않고 값만 비교하는 것. 그래서 ture
값이 출력된다.
var person1 = {
name: 'Lee'
};
var person2 = {
name: 'Lee'
};
console.log(person1 === person2) // ?
console.log(person1.name === person2.name) // ?
은빈님 답:
person1 변수와 person2 변수가 가리키는 객체는 비록 내용은 같지만 다른 메모리에 저장된 별개의 객체다. 즉 두 변수의 참조 값은 전혀 다른 값이다. -> false
하지만 프로퍼티 값을 참고하는 person1.name과 person2.name은 값으로 평가될 수 있는 표현식이다. 두 표현식 모두 원시 값 'Lee'로 평가된다. → true
배운점
비순수함수는 side effect를 불러일으켜서 의도치 않은 코드 변화를 가져올 수 있지만 마냥 나쁜것만은 아님. axios나 useState 처럼 의도적으로 비순수함수 컨셉을 차용하는 사례가 있음