본문 바로가기

JavaScript, HTML, CSS

[JS, 코드 스테이츠]04. 변수의 전달, Scope

목차
1. 변수의 전달
2. 스코프 Scope

 

1.  변수의 전달

  • Primitive Types(원시 타입) scalar type 또는 simple type로도 불림
    • 변수에 할당될 때 메모리 상에 고정된 크기로 저장되고 해당 변수가 원시 데이터의 값을 보관한다.
    • null, undefined, Boolean, Number, String
  • Reference Types(참조 타입) complex type 또는 container type로도 불림
    • 참조 타입 데이터는 크기가 정해져 있지 않다. 변수에 할당될 때 해당 변수에 직접 값이 저장될 수 없으며, 변수에는 데이터에 대한 참조(메모리 주소)만 저장된다. 참조는 참조 타입 데이터의 주소이지 해당 데이터의 값이 아니다.
    • Array, Object, Function
//Copying a primitive
let a = 11;
let b = a;
b = 22;
console.log(a); //13

//Copying a reference
let obj1 = { a: 11 };
let obj2 = obj1;
obj2.a = 22;
console.log(obj1); //{ a: 11 }

[참조]http://codingnuri.com/javascript-tutorial/javascript-primitive-types-and-reference-types.html

 

다른 예제

let array = [ "zero", "one", "two", "three", "four", "five" ];

function passedByReference(refArray) {
refArray[1] = "changed in function";
}
passedByReference(array);
console.log(array[1]); //"changed in function"

let assignedArray = array;
assignedArray[5] = "changed in assignedArray";
console.log(array[5]); //"changed in assignedArray"

let copyOfArray = array.slice();
copyOfArray[3] = "changed in copyOfArray";
console.log(array[3]); //"three"

 


2. Scope

  • let을 사용할 경우 Local Scope 안쪽에서 선언된 변수는 밖에서 사용할 수 없다.
let greeting = 'Hello';
function greetSomeone() {
 let firstName = 'Josh';
 return greeting + ' ' + firstName;
}

greetSomeone(); // => 'Hello Josh'
firstName; // => ReferenceError
//Global Scope에서 Local Scope에 선언된 firstName을 찾았기 때문에 referenceError가 발생

Local Scope vs. Global Scope

  • 안쪽 Scope에서 바깥 변수/함수 접근: 가능
  • 바깥쪽 Scope에서 안쪽 변수/함수 접근: 불가능

  • Scope 중첩 가능(함수 안에 함수 넣는 것 가능)
  • Global Scope: 최상단 Scope. 여기서 생성한 전역 변수는 어디에서든 접근 가능.
  • 지역 변수: 함수 내에서 전역 변수보다 너 높은 우선순위 가짐.
let name = 'R';

let showName = function() {
 let name = 'M';
 console.log(name);
}

console.log(name); //'R'
showName(); //'M'
console.log(name); //'R'

showName = function() {
 name = 'M';
 console.log(name);
}

showName(); //'M'
console.log(name); //'M'

호이스팅 때문에 function을 변수에 넣지 않고 같은 이름으로 선언해서 사용하면 더보기와 같은 출력 값이 나온다.

...더보기
let name = 'R';

function showName() {
 let name = 'M';
 console.log('original showName()', name);
}

console.log(name); //'R'
showName() //'chainged showName() M'
console.log(name); //'M'

function showName() {
 name = 'M';
 console.log('chainged showName()', name);
}

showName() //'chainged showName() M'
console.log(name); //'M'

이 상황에서 위와 같은 현상을 방지하기 위해서는 function을 변수에 저장해서 사용(변경)하거나, showName을 두 번 쓰지 말고 함수의 이름을 다르게 하면 된다.


Function Scope vs. Block Scope

  • Block: 중괄호로 시작하고 끝나는 단위. 주로 if문이나 while문, for문 등에서 쓰임.
  let const var
유효 범위 Block Scope Block Scope Function Scope
값의 재정의 가능 불가능 가능
재선언 불가능 불가능 가능
for(let i = 0; i < 3; i++) {
 console.log(i);
}
console.log('fimal i:', i); //ReferenceError

 

for(var i = 0; i < 3; i++) {
 console.log(i);
}
console.log('fimal i:', i); //3

위의 두 코드를 합쳐놓으면 호이스팅 때문에 위의 i에서 error가 나지 않고 undefined가 된다.

...더보기

자바스크립트의 호이스팅: 코드의 아래쪽에 var형식으로 선언해둔 변수가 있다면 그것을 위로 끌어올려서 undefined로 할당해둔다(실제 작동은 이 설명과 좀 다르다고 함).

for(let i = 0; i < 3; i++) {
 console.log(i);
}
console.log('1. fimal i:', i); //undefined

for(var i = 0; i < 3; i++) {
 console.log(i);
}
console.log('2. fimal i:', i); //3

 

const pi = 3.14;
console.log(pi); //3.14
pi = 3.1415; //TypeError

전역 변수와 window 객체

  • 전역 범위를 대표하는 객체: window
  • Global Scope에서 선언된 함수와 var을 이용해 선언한 변수는 window객체와 연결된다(전역 범위에 선언했기 때문)
  • 전역 범위에서의 선언은 적을수록 좋다.
var tmp = 12;
function foo() {
 console.log('foo');
}

console.log(tmp === window.tmp); //true
console.log(foo === window.foo); //true

선언 없이 초기화된 전역 변수

  • 선언 키워드(var, let, const) 없이 초기화한 변수는 전역 변수로 취급되기 때문에 선언 없이 초기화를 하면 안 됨.
function tmpFunc() {
 tmp = 10;
 console.log(tmp);
}
tmpFunc(); //10
console.log(tmp); //10
  • 위와 같은 실수는 Strict Mode를 사용할 경우 방지할 수 있다.
'use strict';

function tmpFunc() {
 tmp = 10; //에러 발생(ReferenceError)
 console.log(tmp);
}
tmpFunc();
console.log(tmp);