본문 바로가기
Language/JavaScript

[JS] 기초

by 오우영 2021. 1. 25.

 

 

 

1. 배열

순서가 있는 값

 

인덱스(index) [0] [1] [2] [3] [4]
요소(element) 73 98 86 61 96

 

let myNumber = [73, 98, 86, 61, 96]

  • 대괄호(square bracket)를 이용해서 배열을 만듭니다
  • 각각의 요소(element)는 쉼표(comma)로 구분해줍니다

 

Q ) myNumber의 1번째 인덱스 값의 0번째 인덱스 값은?

더보기
let myNumber =[[13,30], [78,8], [44,17]];

myNumber [1] [0];

//78

 

배열의 반복

 

let myNum = [10,20,40,10]

let sum = 0;

for(let n=0;n<myNum.length;n++) {

    sum = sum +myNum[n];
    
}

//sum = 0 + 10 

--> sum 초기값을 지정안해주면 undefined + 10 // NaN

//sum = 10 + 20

//sum = 30 + 40

//sum = 70 + 10

 

배열인지 아닌지 확인하기

 

let words = ['피','땀','눈물'];

let obj = { a:1 }


typeof '문자열';

//"string"

typeof 123

//"number"

typeof words

//"object"

typeof [1,2,3]

//"object"

typeof obj

//"object"

Array.isArray('문자열')

//false

Array.isArray(words) //배열인 words 넣기

//true

Array.isArray([1,2,3]) //직접 배열 넣기

//true

Array.isArray([])  //  빈 배열

//true

 

Q) arr라는 배열이 빈 배열인지 확인하는 알맞은 방법은?

더보기
arr === []

//false

//주소가 다른 빈 배열이라고 생각하기 때문에

arr.length === 0

//true

arr = []

//arr의 값을 []로 바꾸는 코드

Array.isArray(arr) === 0

//Array.isArray는 전달인자의 타입이 배열인지 체크해서 blloean값을 리턴하는 메소드

//0이 나올수가 없다

 

 

배열에서 indexOf, includes 활용

 

let words = ['Redagast', 'the', 'Brown']


words.indexOf('the') //배열의 인덱스 확인

//1

words.indexOf('없는단어')

//-1

words.indexOf('th')

//-1

//문자열과는 달리 처음 발견된 지점이 아닌 요소 값을 모두 입력해야됨


words.indexOf('Brown') !== -1 //배열안에 해당 요소 여부 확인

//true

words.includes('Brown') //Internet Explorer에서는 사용불가

//true

words.includes('없는것')

//false

 

 

 

2. 객체

키와 값 쌍(key-value pair)으로 이루어진 의미를 가지는 값

 

let user = {

      firstName : 'Steve',

      키               

      lastName : 'Lee',

      email : 'steve@codestates.com',

      city : 'Seoul'

};

  • 키, 값 사이는 콜론(:)으로 구분합니다
  • 중괄호(curly bracket)를 이용해서 객체를 만듭니다
  • 키-값 쌍은 쉼표로 구분해줍니다

 

객체를 사용하는 방법 Dot notation과 Bracket notation

 

let user = {

    firstName : 'Steve',
    
    lastName : 'Lee',
    
    email : 'steve@codestates.com',
    
    city : 'Seoul'
    
};


1.Dot notation

user.firstName;

//'Steve'

user.city;

//'Seoul'

//정해진 값에만 적용


2.Bracket notation

user['firstName'];

//'Steve'

user['city'];

//'Seoul'

//key 값이 변할때 주로 사용

 

tweet[content] tweet['content']의 차이

 

let tweet = {

    writer : 'stevelee',
    
    createdAt : '2019-09-10 12-03:33',
    
    content : '프리코스 재밌어요!'
    
};


tweet['content']

//'프리코스 재밌어요!'


tweet[content]

//Uncaught ReferenceError : content is not defined

pi

//Uncaught ReferenceError : pi is not defined

adghjrs

//Uncaught ReferenceError : adghjrs is not defined


//[content]를 변수로 취급


let keyName = 'content';

tweet[keyName]

//'프리코스 재밌어요!'

//content를 새 변수에 할당해주면 tweet['content']와 같아진다


let person = {

    name : 'Steve',
    
    age : 16
    
};

function getProperty(obj, propertyName) {

    return obj[propertyName];  // []에는 문자열 형식을 넣거나 변수를 넣어야함
}

1.

let output = getProperty(person, 'name');

console.log(output);

//'Steve'

2.

let output2 = getProperty(person, 'age');

console.log(output2);

//16

 

 

let tweet = {

     writer : 'stevelee',

     createdAt : '2019-09-10 12:03:33',

     content : '프리코스 재밌어요!'

};

 

dot/bracket notation을 이용해 값을 추가

 

tweet['category'] = '잡담';

tweet.isPublic = true;

tweet.tags = ['#코드스테이츠', '#프리코스']; //배열을 넣어도됨

 

delete 키워드를 이용해 삭제가 가능

 

delete tweet.createdAt; //createAt 키-값 쌍을 지웁니다

//tweet은 다음과 같게 됩니다

// {writer : 'stevelee', content : '프리코스 재밌어요!'}

 

in 연산자를 이용해 해당하는 키가 있는지 확인할 있습니다

 

'content' in tweet;

//true

'updateAt' in tweet;

//false

 

 

Q. 두 개의 객체를 입력받아 두 번째 객체의 속성들을 첫 번째 객체에 추가해야 합니다.

더보기
입출력 예시

const obj1 = { a: 1, b: 2 };

const obj2 = { b: 4, c: 3 };

// 보기의 코드를 여기에 입력하면, 아래의 결과가 나와야 합니다.

extend (obj1, obj2);

console.log(obj1);

//{a:1, b:2, c:3}

console.log(obj2);

//{b:4, c:3}


답

function extend(obj1, obj2) {

  for (let key in obj2) {

    if (!key in obj1) {

      obj1[key] = obj2[key];

  }

 }

}

 

 

 

3. Primitive, Reference, Rest Parameter, Spread operator

 

원시 자료형 (primitive data types)

  • 객체가 아니면서 method를 가지지않습니다
  • string, number, bignit, boolean, underfined, symbol, (null)
  • 모두 '하나'의 정보, 즉, 데이터를 담고 있습니다

const num1 = 123;

const num2 = 1234566789;

 

  • 이렇게 변수에는 데이터의 크기와는 관계 없이 하나의 데이터만 담을 수 있습니다
  • 원시 자료형은 값 자체에 대한 변경이 불가능(immutable)하지만, 변수에 다른 데이터를 할당할 수 있습니다
  • 원시 자료형이 할당될 때에는 변수에 값 자체가 담깁니다
  • call stack 메모리에 저장

 

참조 자료형 (reference type)

  • 원시 자료형이 아닌 모든것
  • 배열, 객체, 함수가 대표적
  • 직접 다루게 되는 변수에는 주소만 저장 (call stack 메모리)
  • 참조 자료형이 할당될 때는 보관함의 주소(reference)가 담깁니다
  • 참조 자료형의 데이터 자체는 heap 메모리에 저장됩니다
  • 원시 자료형처럼 고정된 크기의 보관함이 아니라 동적으로 크기가 변합니다

 

Q1) 코드가 실행된 후, player.score의 값은 무엇일까요?

더보기
let player = {score:3};


function doStuff(obj) {

	obj.score = 2;
    
   }
   
   doStuff(player);
   
   //2
  

 

 

Q2) 코드가 실행된 후, myArray의 값은 무엇일까요?

더보기
let myArray = [2,3,4,5];

let ourArray = myArray;

ourArray[2] = 25;

ourArray = underfined; 

//ourArray에 원시 자료형 underfined가 할당되었기 때문에, myArray에 접근할 수 없습니다

//하지만 myArray는 그대로 유지됩니다

//[2, 3, 25, 5]

 

Rest 파라미터

Rest 파라미터 구문은 정해지지 않은 수를 배열로 나타낼 수 있도록 합니다

 

function f(a, b, ...rest) {

       // ...

}

  • 함수의 마지막 파라미터 앞에 ...를 붙여 (사용자가 제공한) 모든 나머지 인수를 "표준" 자바스크립트 배열로 대체합니다
  • 마지막 파라미터만 "Rest 파라미터"가 될 수 있습니다

Q1) 함수가 실행된후, 콘솔에 출력되는 args의 값은 무엇일까요?

더보기
function printMaxNums(...args) {

	console.log(args)
    
   }
   
   printMaxNums(10, 30, 40)
   
//[10, 30, 40]

 

Q2) 코드가 실행된 후, value의 값은 무엇일까요?

더보기
function findBiggestArg(...args) {

	let biggestArg = 0;
    
    for(let i=0; i<args.length; i++) {
    	
        if (biggestArg < args[i] {
        
        	biggestArg = args[i]
          
          }
          
        }
        
        	return biggestArg
        
        }
        
        let value = findBiggestArg(10, 30, 40, 20)
        
 //40

 

spread operator

전개 구문은 배열이나 문자열과 같이 반복 가능한 문자를 펼쳐주는 문법을 의미합니다

 

const arr = [1, 2, 3, 4, 5]

const newArr = [...arr]

 

//[1, 2, 3, 4, 5]

 

 

Q) 코드가 실행된 후, value값은 무엇일까요?

더보기
let arr = [10, 30, 40, 20]

let value = Math.max(...arr)

//Math.max(10, 30, 40, 20)

//40

 

 

 

4. scope

변수 접근 규칙에 따른 유효 범위

 

  • 변수는 어떠한 환경 내에서만 사용 가능하며, 프로그래밍 언어는각각의 변수 접근 규칙을 갖고 있습니다
  • 변수와 값이, 어디서부터 어디까지 유효한지를 판단하는 범위
  • JavaScript는 기본적으로, 함수가 선언되는(lecical) 동시에 자신만의 Scope를 가집니다

 

Local Scope과 Global Scope의 차이

 

let greeting = 'Hello';

function greetSomeone() {

    let firstName = 'Josh';

    return greeting + ' ' + firstName;

}

    greetSomeone();

    //'Hello Josh'

    firstName;

    //ReferenceError

 

  • 변수 firstName에 접근할 있는 범위가 존재
  • Local Scope 안쪽에서 선언된 변수는 밖에서 사용할 없습니다
  • 안쪽 Scope에서 바깥 변수/함수를 접근하는 것은 가능
  • 바깥쪽 Scope에서 안쪽 변수/함수를 접근하는 것은 불가능
  • Scope는 중첩이 가능합니다
    -함수 안에 함수를 넣을 있습니다
  • Global Scope는 최상단의 Scope로 전역 변수는 어디서든 접근이 가능합니다

 

let name = "Richard";

function showName() {

    let name = "Jack"; //지역 변수, showName 함수 안에서만 접근 가능

    console.log(name); //2, Jack
    
}

    console.log(name); //1, Richard
    
    showName();

    console.log(name); //3, Richard


let name = "Richard";

function showName() {

    name = "Jack"; //전역 변수, showName 함수 안에서만 접근 가능

    console.log(name); //2, Jack
    
}

    console.log(name); //1, Richard
    
    showName();

    console.log(name); //3, Jack

 

Function Scope과 Block Scope (= lexical scope)의 차이

Block : 중괄호로 시작하고 끝나는 단위

 

var

- 함수 단위로 자신만의 Scope를 가집니다

 

let

- Block단위로 Scope를 구분합니다

 

 

function greetSomeone(firstName) {

    var time = 'night';
    
    if(time === 'night') {
    
        var greeting = 'Good Night';
        
    }
    
    return greeting + ' ' + firstName;
    
}

greetSomeone('Steve');


//Good Night Steve


function greetSomeone(firstName) {

    let time = 'night';
    
    if(time === 'night') {
        var greeting = 'Good Night';
        
    }
    
    return greeting + ' ' + firstName;
    
}

greetSomeone('Steve');


//안쪽 함수에 접근이 불가능해 안쪽 함수 firstName 값이 undefined

//작동 안됨

 

변수 var let const
유효 범위 Function Scope Block Scope Block Scope
재선언 o x x
재할당 o o x

 

  • const
    constant(상수)를 뜻합니다. 즉, '항상 같은 수'를 말합니다

    상수이기 때문에 const 키워드로 선언하면 변치 않는 값을 갖는 변수를 생성합니다
    그렇기에 const로 선언한 변수는 값을 재할당할 수 없습니다

    const myName = 'Wo Young';
    myName = 'O';  // TypeError: Assignment to constant variable

    const 변수는 반드시 값이 할당되어야 합니다
    값 없이 선언하면 SyntaxError 메시지가 뜹니다

    const name;
    console.log(name); //Syntaxerror: Missing initializer in const declaration


  • let
    let은 const와 다르게 다른 값이 재할당될 수 있습니다

    let fruit = 'banana';
    fruit = 'apple';

  • var
    let, const와 다르게 변수 재선언이 가능합니다

    var age = 30;  //  결과 : 30 (초기 변수 선언)
    age = 28;  //  결과 : 28 (변수값 재할당)
    var age = 'old';  //  결과 : 'old' (변수 재선언)

 

전역변수와 window 객체

  • 전역 범위를 대표하는 객체 window
  • Global Scope에서 선언된 함수, 그리고 var 키워드를 이용해 선언된 변수는 window 객체와 연결
  • 전역 범위에 너무 많은 변수를 선언하지는 말자

 

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

선언 키워드 (var, let, const)없이 변수를 초기화하지 마세요

 

function  showAge() {

    age = 90; //age는 전역 변수로 취급
    
    console.log(age);
    
}

//age === window.age

//오류가 많이 나게된다 (좋은것이 아님)


showAge();

//90

console.log(age);

//90

 

 

Q) 다음의 코드를 실행시킨 후에 result의 값은 무엇이 될까요?

더보기
let x = 10;

function outer() {

	x = 20;
    
    function inner() {
    
    	let x;
        
        x = x + 20;
        
        return x;
        
        }
        
        inner();
        
        }
        
        outer();
        
        let result = x;
        
   //20

 

 

5.closure

함수와 함수가 선언된 어휘적 환경의 조합

 

function outerFn() {

    let outerVar = 'outer';
    
    console.log(outerVar);
    
    function innerFn() {
    
        let innerVar = 'inner';
        
        console.log(innerVar);
        
    }
    
    return innerFn;
    
}



outerFn();

/*function innerFn() {

     let innerVar = 'inner';

     console.log(innerVar);

 } */


outerFn()()

//inner


let innerFn = outerFn();

//outer


innerFn();

//inner

 

  • 외부 함수의 변수에 접근할 수 있는 내부 함수
  • 클로저 함수 안에서는 지역 변수 외부 함수의 전역 변수의 접근이 전부 가능합니다

 

커링

함수 하나가 n개의 인자를 받는 대신, n개의 함수를 만들어 각각 인자를 받는 방법

 

function adder(x) {

    return function(y) {
    
        return x+y;
        
    }
    
}

adder(2)(3); //5

let add100 = add(100); //x의 값을 고정해놓고 재사용할 수 있다

add100(2); //102

add100(10); //110

 

외부 함수의 변수가 저장되어 마치 템플릿 함수와 같이 사용 가능

 

function htmlMaker(tag) {

    let startTag = '<' + tag + '>';
    
    let endTag = '</' +tag + '>';
    
    return function(connect) {
    
        return startTag + content + endTag;
        
    }
    
}

    let divMaker = htmlMaker('div');
    
    divMaker('code'); //<div>code</div>
    
    divMaker('states'); //<div>states</div>
    
    let h1Maker = htmlMaker('h1');
    
    h1Maker('Headline'); //<h1>Headline</h1>

 

클로저 모듈 패던

변수를 스코프 안쪽에 가두어 함수 밖으로 노출시키지 않는 방법

 

function makeCounter() {

    let privateCounter = 0;
    
    return {
    
        increment: function() {
        
            privateCounter++;
            
        },
        
        decrement: function() {
        
            privateCounter--;
            
        },
        
        getValue: function() {
        
            return privateCounter;
            
        }
        
    }
    
}
위와 동일 코드
/*
function makeCounter() {

    let privateCounter = 0;
    
    let obj = {
    
        increment: function() {
        
            privateCounter++;
            
        },
        
        decrement: function() {
        
            privateCounter--;
            
        },
        
        getValue: function() {
        
            return privateCounter;
            
        }
        
    }
    
    return obj;
    
}
*/

let counter1 = makeCounter();

counter1.increment();

counter1.increment();

counter1.getValue();

//2


let counter2 = makeCounter();

counter2.increment();

counter2.decrement();

counter2.increment();

counter2.getValue();

//1

// privateCounter를 간접적으로 바꿀수가 있다

let counter2 = makeCounter();

counter2.increment()

counter2.increment()

counter2.increment()

counter2.increment()

counter2.increment()

counter1.getValue()

//5

 

  • privateCounter를 각각 독립적으로 가지고 있기때문에
  • 두 카운터에 각기 다른 privateCounter를 다루면서, privateCounter를 밖으로 노출시키지 않는다

 

funtion makePayment() {

    let type = '현금';  // 반드시 '현금' 또는 '카드'여야 함
    
    return {
    
        payWithCash: function(amount) {
        
            type = '현금';
            
            console.log(type +'으로' + amount + '만큼 지불합니다.');
            
        },
        
        payWithCard: function(amount) {
        
            type = '카드';
            
            console.log(type +'으로' + amount + '만큼 지불합니다.');
            
        }
        
        } 
        
    }
    
}

 

  • 프로그램 외부에서 type을 마음대로 바꿀수가 없다
  • 현금, 카드로만 들어갈수 있도록 간접적으로만 바꿀수 있도록 세팅

 

클로저의 단점

 

일반 함수였다면 함수 실행 종료 후 가비지 컬렉션(자동 메모리 관리법) 대상이 되었을 객체가 클로저 패턴에서는 메모리 상에 남아 있게 됩니다. 외부 함수 스코프가 내부함수에 의해 언제든지 참조 될 수 있기 때문입니다. 따라서 클로저를 남발할 경우 퍼포먼스 저하가 발생할 수도 있습니다.

 

 

Q) total의 값은 무엇일까요?

더보기
let add = function(x) {

	let sum =  function(y) {
    	
        return x + y;
        
        }
        
        return sum;
        
        }
        
        let foo = add(1);
        
        foo(3);
        
        let total = foo(6);
        
   //7

'Language > JavaScript' 카테고리의 다른 글

[JS] OOP  (0) 2021.02.26
[JS] 구조 분해  (0) 2021.02.25
[JS] 화살표함수  (0) 2021.02.24
[JS] 고차함수  (0) 2021.02.24
[JS] Method  (0) 2021.01.19

댓글