package main
import "fmt"
var d string //package level scope
func main() {
var a bool
var b int
var c float32 //block level scope
fmt.Println(a) //false
fmt.Println(b) //0
fmt.Println(c) //0
fmt.Println(d) //
}
여러개 한번에 선언
package main
import "fmt"
func main() {
var (
name string = "name"
age int32
)
age = 25
fmt.Println(name) //name
fmt.Println(age) //25
}
짧은 선언
반드시 제한된 범위의 함수 내에서 사용(전역으로는 사용 불가) => 코드 가독성을 높일 수 있다.
선언 후 재할당 하면 예외 발생한다. 즉, 짧은 선언은 1회성으로 메소드 안에서만 사용하는 경우 명시적으로 알려주는 기능
package main
import "fmt"
func main() {
age := 3 // 내부적으로 알아서 int 할당
// age := 10 -> 에러 발생: "no new variables on left side of :="
fmt.Println(age)
//언제 사용하는지? 예시
if i := 10; i < 11{ // i는 if문 밖에서는 사용 불가, if문이 끝나면 소멸된다.
fmt.Println("test")
}
}
상수
const로 사용하며 선언과 동시에 초기화, 한번 선언 후에는 값 변경 금지
함수 리턴값을 받을 수 없다.
// 위와 같이 한줄씩, 여러개 한꺼번에 선언하는 방식 모두 가능하다
const a, b int = 1, 2
const c, d = "Hi", false
const (
x, y int = 16, 21
)
열거형
연속된 성질의 상수를 나열할 때 사용한다. (자바의 enum class와 비슷...?), 일정한 규칙에 따라 나열된 수
iota를 적절히 활용해서 초기화 할 수 있다.
package main
import "fmt"
func main() {
const (
x = iota
y
z
)
fmt.Println(x, y, z)
const (
_ = iota
a // 1
_ // 생략하고 싶은 부분은 _로 스킵 가능하다.
b // 3
c // 4
)
fmt.Println(a, b, c)
}
제어문과 반복문
if문
반드시 boolean만 검사 (자동 형 변환 불가)
엄격한 form을 요구 - 줄맞춤이 중요하다, 괄호 생략하면 안됨
package main
import "fmt"
func main() {
const a int = 4
if a < 11{ // 여는 괄호가 아랫줄로 가면 오류남
fmt.Println("1")
} else if a < 5 { // else if 또는 else는 닫는 괄호 바로 뒤에 위치해야 한다
fmt.Println("2")
} else {
fmt.Println("3")
}
}
switch문
if문에서 할 수 있는 모든 조건을 switch문에서 할 수 있다.
switch/case 뒤 expression 생략 가능
기본적으로는 자동 break => fallthrough 넣으면 다음 case문을 실행한다. (마지막 케이스에는 fallthrough넣으면 오류)
type 분기 => 값이 아닌 타입으로 분기 가능
package main
import "fmt"
func main() {
a := 7
switch {
case a > 0: // case 인덴트는 switch 위치와 동일해야
fmt.Println("양수 ", a)
case a == 0: // case문에 && || 연산자 모두 사용 가능
fmt.Println("0 ", a)
case a < 0:
fmt.Println("음수 ", a)
}
switch b := 7; { // 범위가 정확히 switch문으로 제한된다 (scoped)
case b > 0: // 위 case문과 동일하다. go에서는 이렇게 더 많이 씀
fmt.Println("양수 ", b)
case b == 0:
fmt.Println("0 ", b)
case b < 0:
fmt.Println("음수 ", b)
}
switch i, j := 7, 8; { // 여러개도 가능
case i < j:
fmt.Println("i < j")
case i == j:
fmt.Println("i == j")
case i > j:
fmt.Println("i > j")
}
switch c := "GO"; c {
case "GO": // c == "GO" 해줄 필요 없음
fmt.Println("go")
case "JAVA":
fmt.Println("java")
default:
fmt.Println("불일치")
}
switch c := "GO"; c + "LANG" { // 이 영역에서 연산도 가능하다
case "GOLANG", "GO": // 다양한 값 매칭 가능
fmt.Println("go")
case "JAVA":
fmt.Println("java")
default:
fmt.Println("불일치")
}
}
for문
go에서는 while 없음, 반복문은 for만 제공된다
if와 마찬가지로 괄호 위치 중요하다
자바처럼 루프에 label을 주고 continue, break에 사용할 수 있다
continue, break 다른 언어와 동일하게 사용할 수 있다
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ { // 괄호 여부 및 위치 중요, i++ 대신 i = i+1 이런식으로 해도 된다
fmt.Println(i) // 0~4 출력
}
j := 0
for j < 5; { // 위와 동일
fmt.Println(j) // 0~4 출력
j++ // 주의 후치연산은 go에서 리턴값이 없음 -> k := j++ -> 컴파일 에러
}
//무한루프 패턴
sum, k := 0, 0
for {
if i > 100 {
break
}
sum += i
i++
// ++i -> c.f. 전치 연산자는 go에서 정의하지 않음, 컴파일 에러난다.
}
//range용법
location := []string{"Seoul", "Incheon", "Busan"}
for index, name := range loc { //첫번째로 가져오는 것은 무조건 인덱스
fmt.Println(index, name)
}
location := []string{"Seoul", "Incheon", "Busan"}
for _, name := range loc { //인덱스 안가져오고 싶은 경우엔 이렇게 하면 된다
fmt.Println(index, name)
}
}
run: 작성한 go 파일을 컴파일 없이 실행한다 - 작성 후 테스트 할 때 주로 사용 (atom: cmd+i)
build: 실행하지 않고, 실행 가능한 바이너리 파일로 빌드해서 해당 폴더에 만들어 준다. 파일명은 작성한 코드의 파일명과 동일
install: src에 있는 여러 폴더들을 하나의 애플리케이션이라고 하고, src에서 참조하는(의존관계에 있는) 외부 라이브러리 패키지들이 들어있는 pkg 폴더 등을 포함해서 최종적으로 실행 가능한 파일로 컴파일 해서 bin 폴더 아래에 만들어준다. 이때 파일명은 소스 파일들이 있는 상위 폴더명이다.
godoc -http=:8080: 로컬호스트에서 go 엔진에서 가지고 있는 서버가 실행됨, 레퍼런스 문서를 로컬호스트에서 확인 가능하다
atom 에디터에서 go-plus, script, platformio-ide-terminal을 설치해준다
배운점
- 왜 나는 bash_profile을 설정했는데도 터미널을 새로 켤때마다 source ~/.bash_profile을 해 줘야하는 것인가?
=> 이 문제 때문에 go-plus도 제대로 실행되지 않음ㅠㅠ
이유는 zsh를 사용하고 있었기 때문이었다. bash를 기본으로 사용하고 있으면 .bashrc -> .bash_profile 순으로 실행되지만,
mac 기본 쉘이 zsh를 사용하고 있었기 때문에 .zshrc -> .bash_profile이 실행될 수 있도록 아래와 같은 부분을 추가해준다.
// ~/.zshrc 에 아래 부분 추가
if [ -f ~/.bash_profile ]; then
. ~/.bash_profile
fi
+ 추가) bash_profile vs bashrc vs zshrc ?
bash_profile: 시스템에 로그인할 때마다 실행 = only sourced whenbashis started as an interactive login shell, or as a non-interactive shell with the `--login` option
bashrc: 이미 로그인한 상태에서 새 터미널 창을 열때마다 실행 = sourced on every start in interactive mode whenbashdoes not act as a login shell.
zshrc: bash와 같은 쉘의 한 종류인데, 맥 터미널이 디폴트로 사용하고 있다. zshrc는 bashrc와 다르게 login/non-login 모두 상관 없이 실행된다.
첨에 gomodule이 뭔지도 모르고 프로젝트를 시작해서 gopath 등 환경변수 세팅하는데 애먹었었는데..
알고보니 이런 불편한 점들을 개선하기 위해 gomodule이라는 방식으로 개발하면 된다고 함
개발하고자 하는 패키지에서 아래 명령어로 go.mod 파일을 생성한 뒤, main.go 함수를 추가하고 개발하면 된다고 한다..
import java.util.Scanner;
public class Solution {
public static int max = 0;
public static void main(String[] args) throws Exception {
Scanner in = new Scanner(System.in);
int testcase = in.nextInt();
for (int t = 1; t <= testcase; t++) {
max = 0;
int n = in.nextInt();
int limitCalories = in.nextInt();
int ingredients[][] = new int[n][2];
for (int i = 0; i < n; i++) {
ingredients[i][0] = in.nextInt();// 맛
ingredients[i][1] = in.nextInt();// 칼로리
}
for (int i = 0; i < n; i++) {
findMaxTaste(i, ingredients[i][0], ingredients[i][1], ingredients, limitCalories);
}
System.out.println("#" + t + " " + max);
}
}
public static void findMaxTaste(int index, int taste, int calories, int ingredients[][], int limit) {
if (calories > limit || index == ingredients.length) {
return;
}
max = Math.max(max, taste);
for (int i = index + 1; i < ingredients.length; i++) {
if (calories + ingredients[i][1] <= limit) {
findMaxTaste(i, taste + ingredients[i][0], calories + ingredients[i][1], ingredients, limit);
}
}
}
}
웹 애플리케이션에 js framework나 라이브러리를 바로 사용할 수 있는 호스팅 서비스
(Vue Cli만 사용해 보았었는데 CDN도 마찬가지로 Vue의 기능을 모두 사용할 수 있다고 한다. CDN 방식의 경우는 빌드 등을 할 필요 없이 파일만 클릭하면 html 파일이 띄워 졌다.)
그래서 CDN은 결국 서버에 보내는 request이고, 브라우저는 한 시점에 제한된 개수(5~6개??)의 request를 요청할 수 있기 때문에 CDN으로 가져오면 request가 하나 늘어나는 것이나 다름 없으므로 url로 부터 리소스를 가져올 것이 많은 경우에는 결과적으로 페이지를 볼 수 있을 때까지 조금 더 기다리게 된다고 한다.
다른 이유로는
script 태그로 참조하여 사용하는 방법으로는 SPA(Single Page Application) 앱을 개발할 수 없기 때문에 대부분 Vue CLI 도구를 이용
Vue CLI를 이용해 개발하면 .vue 파일로 분리된 단일 파일 컴포넌트 단위로 컴포넌트 중심의 개발을 합니다. 개발된 컴포넌트를 조합하여 UI를 구성한다. 개발된 코드는 webpack에 의해서 빌드 및 번들링된 후 배포버전의 html, css, js 파일을 생성한다. (하나의 html 파일로 만듦)
⇒ 스크립트 태그로 참조하는 방식은 이게 불가능함
HTML id vs class?
id는 한 페이지에 하나의 style/css로 하나의 태그만 사용할 수 있다. 따라서 로고, 상단 메뉴, 하단 정보와 같은 스타일을 정의할 때 사용한다. el 지정을 할 때 .app 이런 식으로 정의해야 함
class는 한 페이지에 반복적으로 사용 되는 스타일을 정의할 수 있다. el 지정을 할 때 #app으로 정의한다.
반복적으로 사용 되는 스타일에는 class, 그 내부에 세부 스타일에는 id를 사용하면 효과적이다.
⇒ 객체를 굳이 지정하지 않은 경우에는 id를 써 주지 않도록 함!!!
* 브라우저가 id는 매우 빠르게 접근이 가능하게 별도로 관리 한다. class나 tag의 경우 css query 방식을 이용한다.
v-if는 v-show와 같이 특정 html 요소를 보이거나 감추는 역할을 한다. 두 디렉티브의 차이는 DOM을 만드는지 여부에 달려 있는데, v-if는 아예 DOM 요소를 만들어내지 않고, v-show는 DOM 요소를 만들되 display:none 효과를 가져온다.
즉, v-if는 조건에 따라 컴포넌트가 실제로 제거되고 생성되고,
반면에 v-show 는 단순히 css 의 display 속성만 변경된다
v-for과 v-if 같이 사용 시 v-for이 더 높은 우선순위를 가진다.
Vue의 v-for 동작 방식
렌더링 된 엘리먼트 목록을 갱신할 때 기본적으로 in-place patch 전략을 사용한다. 이 것은 데이터 항목의 순서가 변경된 경우, 항목의 순서와 일치하도록 DOM 요소를 이동하는 대신 Vue가 각 요소를 적절한 위치에 패치하고 해당 인덱스에서 렌더링할 내용을 반영하는지 확인하는 것이다.
(여기서는 필요 없겠지만??) Vue에서 개별 DOM 노드들을 추적하고 기존 엘리먼트를 재사용/재정렬하기 위해서는 v-for의 각 항목들에 고유한 key 속성을 제공해야 한다. key속성은 v-bind를 사용하여 동적 값에 바인딩 한다.
반복되는 DOM 내용이 단순한 경우나 의도적인 성능 향상을 위해 기본 동작에 의존하지 않는 경우를 제외하면, 가능하면 언제나 v-for에 key를 추가하는 것이 좋다고 한다. (key 값은 primitive 속성인 것을 사용하도록)
편의를 위해서, v-bind를 생략 할 수 있다. 그냥 콜론 뒤에 속성의 이름만 넣어 주면 됨
예) v-bind:key ⇒ :key
v-for는 v-if 보다 더 높은 우선순위를 가지고 있기 때문에 두 디렉티브를 같이 사용하는 방법은 추천하지 않는다고 한다. 일반적으로 두 디렉티브를 같이 쓰고 싶을 경우는 조건부 필터링을 하고싶을 때 이다. 굳이 v-if을 사용하고싶다면 아래 두 방법을 사용하면 된다.
//1. 상위나 하위에 n
<ul v-if="shouldShowUsers">
<li
v-for="user in users"
:key="user.id"
>
{{ user.name }}
<li>
</ul>
Webpack
대규모 응용 프로그램 같은 경우에는 js모듈이 많기 때문에 대부분 module bundler 라는 것을 이용한다고 한다. 모듈 번들러는 웹 애플리케이션을 구성하는 자원(HTML, CSS, Javscript, Images 등)을 모두 각각의 모듈로 보고 이를 조합해서 병합된 하나의 결과물을 만드는 도구를 의미함... NPM으로 vue를 땡겨서 webpack 같은 걸로 관리하게 되는데, Vue CLI로 가져오게 되면 이런 것 크게 신경 쓸 것 없이 미리 다 세팅이 되어 있다고 함. 그리고 개발 시에 핫 리로드, lint-on-save 이런 기능도 설정이 되어 있다고 한다. 이게 뭔지는 나중에 알아보고... webpack 같은 모듈 번들러만 쓰는 경우에는 특별히 세팅 하지 않으면 빌드 후에 app.js 와 같이 모든 js가 하나의 파일로 묶이는데 이게 용량이 금방 늘어 난다고 한다. (chunk로 split 해주지 않으면)
웹팩은 entry로 설정된 시작점에서 의존성을 가진 모든 파일을 압축하여 output 지점에 하나의 자바스크립트 파일을 만들어 준다. 이때, 자바스크립트가 아닌 파일은 loaders를 이용하여 자바스크립트에서 이용가능한 모듈로 만들어 주며, plugins를 이용하여 번들된 자바스크립트를 난독화하거나 특정 텍스트를 추출하는 역할을 합니다. mode는 웹팩의 사용 목적에 따라 설정을 지정하는 역할을 합니다.
+추가)
웹팩은 모든 파일을 모듈로 바라본다. 자바스크립트로 만든 모듈 뿐만아니라 스타일시트, 이미지, 폰트까지도 전부 모듈로 보기 때문에 import 구문을 사용하면 자바스크립트 코드 안으로 가져올 수 있다.
이것이 가능한 이유는 웹팩의 로더 덕분이다. 로더는 타입스크립트 같은 다른 언어를 자바스크립트 문법으로 변환해 주거나 이미지를 data URL 형식의 문자열로 변환한다. 뿐만아니라 CSS 파일을 자바스크립트에서 직접 로딩할수 있도록 해준다.
웹팩은 기본적으로 필요한 자원은 미리 로딩 하는게 아니라 그 때 그 때 요청하자 → Lazy Loading
c.f. webpack-dev-server (서버 구성은 Node.js 환경 위에 Express 서버 프레임워크가 올라간 형태)
localhost의 8080 포트로 개발서버를 실행하게 된다. 브라우저로 http://localhost:8080 요청을 보내면, HTML, JavaScript, CSS 를 응답으로 받고 자바스크립트가 index.html 의 <div id="app"></div> 부분에 vue 컴포넌트를 동적으로 그려 준다.
웹팩 데브 서버로 빌드한 결과물은 메모리에 저장되고 파일로 생성하지는 않기 때문에 컴퓨터 내부적으로는 접근할 수 있지만 사람이 직접 눈으로 보고 파일을 조작할 순 없다. ⇒ 괜히 dist 폴더에 뭐가 안생기는지 찾았네...
암튼 그래서 컴퓨터 구조 관점에서 파일 입/출력보다 메모리 입출력이 더 빠르고 컴퓨터 자원이 덜 소모된다.
즉, JavaScript에서 자식 요소에 직접 접근할 때 사용한다. 이 경우, ref 속성을 이용해 자식 요소에 레퍼런스 ID를 할당하여 해결한다.
주의할 점은 $refs는 랜더링 된 후 값이 채워진다. 또한 $refs는 반응형이 아니라고 함.(즉, $refs가 변경 되어도 watch, computed 등으로 감지 하지 못함) 그렇기 때문에 template에서나 computed에서 $refs를 사용할 수 없다.
vue에서 포커스 주는 법
포커스 될 input 태그에 ref 값을 설정하고 원하는 methods 에 this.$refs.설정값.focus() 입력
v-model
Vue에서 양방향 바인딩을 가능하게 한다.
데이터 바인딩이란 VueJs의 binding expressions을 사용하여 script와 DOM간의 데이터를 주고받는 과정을 의미
단방향 바인딩은 데이터를 화면에 출력
양방향 바인딩은 화면에서 입력을 받아 데이터로 다시 전달하는 과정이 추가되어, 양쪽 방향 모두 바인딩 되는 것을 의미한다.
주의할 점
v-model은 value, checked, selected와 같은 어트리뷰트들을 깔끔히 무시하고, 오로지 vue 인스턴스의 data 속성을 유일하게 보기 떄문에, 초기값 설정을 꼭 해줘야 한다.
## v-bind vs v-model
input 엘리먼트에 v-model을 사용하여 Vue 인스턴스의 데이터를 바인딩하면 입력한 내용에 대해 모델 바인딩 바로 되지만, v-bind를 사용했을 경우 그렇지 못하기 때문에 $event.target.value를 사용하여 값을 가져와 oninput 이벤트에 데이터 값을 변경해준다.
왜 v-model이 computed로는 setter가 안됐을까? 왜 watch 만 가능한 것인가...ㅠㅠ
=== : Identity, 일치 연산자로, 형 변환을 하지 않고 두 피 연산자를 더 정확하게 비교한다.
0 === '' //false
0 === false //false
1 === true //false
NaN === NaN //false
null === undefined //false
mixin
다중 상속이나 재사용을 위해 구현한 인터페이스
믹스인을 통해 다른 컴포넌트들은 캡슐화된 기능을 사용할 수 있다. 결과적으로 같은 동작이지만, 서로 다른 실행을 통해 처리된다.
거의 기능을 선언하는 부분으로, js문법을 통해서 만들었다. (abstract class같은 느낌)
→ 혼자서는 암것도 못하고 다른 컴포넌트에게 mixin되서 사용된다.
- 동일한 이름의 함수가 선언될 때
var mixin = {
methods: {
foo: function () {
console.log('foo')
},
conflicting: function () {
console.log('from mixin')
}
}
}
var vm = new Vue({
mixins: [mixin],
methods: {
bar: function () {
console.log('bar')
},
conflicting: function () {
// => 오버라이딩(?)처럼 되어서 vm.conflicting을 할 경우 vm에서 정의된 함수가 호출된다.
console.log('from self')
}
}
})
mixin은 편리하지만 mixin을 사용한 vue파일에 공통적으로 추가 됩니다. 이렇게 되면 동일한 코드가 반복되서 사용되는 문제가 있습니다. 만약 상수값을 공통적으로 사용하려고 mixin안에 담는다면 동일한 코드가 반복될것입니다. 그리고 내용의 크기가 크다면 더 좋지못한 영향을 끼치게 될것입니다. 상수를 효율적으로 처리하기위해선 상수를 관리하는 vueX를 사용하기를 권고합니다.
Javascript 변수 종류
var: es6 이전의 변수 선언 방식, 매우 유연한 방식으로 변수를 선언할 수 있는 방법이다.
단점: 넘 유연해서 같은 변수를 두번 선언 해도, 잘 동작한다.
let: es6 이후에 추가됨, 값을 재정의 가능, scoped, 같은 변수를 두 번 선언하는 것은 불가
const: es6 이후에 추가됨, 상수 표현, scoped
⇒ var 보다는 let, const로 명확하게 표현하도록 하자!
axios
axios는 통신할 때만 쓰는 줄 알았는데, 데이터를 읽을 때도 쓸 수 있다는 걸 알았다. ⇒ 통신맞다.. webpack dev 서버를 쓰느라...
response 자체는 아래와 같이 생겼다. data 말고도 다양한 필드가 존재함 ⇒ 내부 폴더에 저장되어 있는 파일을 그냥 읽는 식이 아니고, dev server를 이용하여 get으로 가져온 것
엄청 옛날에는... connection을 한 번 열릴 때마다 thread를 하나씩 만들어서 처리 했다고 한다. CPU가 여러 개의 쓰레드를 처리 하려면 컨택스트 스위칭이 일어나게 되는데, 이 컨택스트 스위칭이 일어나게 되면 속도 저하가 일어난다.
이후에는 task 기반이라는 것이 나오는데, thread가 아닌 태스크라는 논리적인 단위를 만들어서 각 단위를 쓰레드마다 주게 된다. 이 방법은 쓰레드를 바꾸지 않기 때문에 컨택스트 스위칭 비용이 발생하지 않게 된다. ⇒ async/await 가 task 기반으로 돌아가는 것임
즉, axync, await가 쓰레드를 만드는 것 보다는 속도 성능이 좋다.
그치만 async도 오버헤드가 있긴 함...
⇒ 결과적으로는 웹 서버에 처리해 줄 수 있는 thread pool에 있는 task수와 request 수가 비슷하면 뭘 쓰든 성능이 비슷하다.
그런데, 만약 request 수가 많아지게 되면, async를 쓰게 되면 request를 실행하다가 잠깐 멈추고 다른 request를 실행하는 형식으로 왔다 갔다 동작하게 된다. (1개의 job이 빨리 끝나는 것은 아니지만, 모든 사람의 job이 모두 느리게 끝나진 않는다)
⇒ 그래서 웹 프론트에서 동기 방식을 쓰면 페이지가 안뜨는 건가 보다...
async를 안 해주게 되면, 뒤에 온 request는 앞에 온 request가 끝날 때까지 기다려야 한다. 그럼 이 처리를 할 때 어떤 것이 문제가 생겨서 걸리는 시간이 길어지게 된다면? 뒤에 기다리는 작업은 time out이 발생할 수 있다. ⇒ scalability가 중요하니까 쓰는거임
async/await, promise는 non-blocking 방식이다.
async/await는 비동기 코드의 겉모습과 동작을 좀 더 동기 코드와 유사하게 만들어준다. 이것이 async/await의 가장 큰 장점이다.
콜백 함수: 어떤 이벤트가 발생한 후, 수행될 함수로, 아래는 주의할 점이다.
콜백함수는 클로저이다.
클로저는... 이미 생명 주기가 끝난 외부 함수의 변수를 참조하는 함수를 뜻한다. js는 함수형 언어이기 때문에 아래 코드와 같이 inner() 함수의 유효 범위(scope) 밖에서, 즉 outer() 내부에 존재하고 inner() 함수 외부에 존재하는 변수, 함수에 접근할 수 없지만, JS에서는 클로저를 통해 접근할 수 있으며 또한 값을 변경할 수도 있다.
function outer(){
var x = 10;
function inner(){
x++; // 밖에 있는 x에 접근 가능
console.log(x)
};
return inner;
}
콜백함수 사용 시 this 객체에 유의해야 한다.
this는 뭐냐면... js의 경우 함수 호출 방식에 의해 this에 바인딩할 어떤 객체가 동적으로 결정된다. 다시 말해, 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다.
즉, 함수가 불러지기 위해 필요한?(접근해야 하는??) 대상이 this가 된다.
var person = {
name: "victolee",
email: "asdf@example.com",
birth: "0225",
foo : function(){
console.log(this) // this == person 객체
}
}
/*객체가 메서드를 호출할 경우, 메서드를 호출한 객체가 this이다.*/
person.foo() // foo() 함수를 실행하기 위해서는 person 객체의 foo 프로퍼티를 참조해야
// 즉, foo() 함수를 호출한 것은 person 객체이므로, this는 person 객체를 가르킵니다.
var x = 10;
function foo(){
this.x = 20;
x = 30;
console.log(x);
console.log(this.x);
console.log(window.x);
}
/*일반 함수인 경우, 브라우저 상에서 window가 this이다.*/
foo() // 어떤 객체가 호출한 것이 아니기 때문에, this는 특정 객체를 가르키고 있지 않음
// 일반 함수일 경우에는 window 객체를 this로 갖고 있습니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
</head>
<body>
<button class="btn" value="foo">버튼</button>
</body>
<script>
/*이벤트가 발생한 경우, 이벤트를 발생한 객체가 this이다.*/
$(".btn").click(function(){ // 버튼 클릭 시 click 이벤트가 실행된다.
console.log(this) // 이벤트가 발생했을 때는 이벤트가 발생한 객체가 this
})
</script>
</html>
js는 this를 명시적으로 바인딩할 수 있는 apply, call, bind 메소드 를 제공한다... 이건 또 뭐냐면
vue.js, 즉 DOM에 한해서는 함수를 호출한 객체, 이벤트가 발생한 객체가 아니면 대부분의 this는 기본 값인 window가 된다. 명시적 바인딩 함수는 this를 조작 할 수 있는 메서드로서, 원하는 객체를 this로 할당하고 싶을 때 사용한다.
call()과 apply() 메서드의 차이
함수를 호출할 때 this를 바꿔주는 기능은 같지만 매개변수로 인자들을 넘겨줌 → call
배열을 넘겨 줌 → apply
var person = {
name: "victolee",
email: "asdf@example.com",
birth: "0225",
foo : function(val1, val2, val3){
console.log(val1 + val2 + val3);
console.log(this);
}
}
person.foo.call(window, 3,6,9); // foo의 this 객체를 person에서 window로 변경
// 이렇게 되면 call() 메서드를 호출할 때 첫 번째 인자로 window 객체를 전달했으므로 this는 window 객체로 변경됨
배열 변수 렌더링?
boolean 배열로 변수를 정의하고 있을 경우, arr 요소 중에 boolean의 값을 바꿨을 경우, 재 렌더링을 하지 않아서 force update를 해 주었다.
이렇게 된 이유는 Vue는 data에 arr이 변경 되었을 경우에만 감지를 할 수 있는데, arr 안에 있는 bool의 값을 변경했기 때문에 arr의 주소 값은 변경 없이 그대로 이기 때문이다.
data에 바인딩 되어있는 속성의 주소 값이 변경 되어야만 Vue는 변화를 감지하고 re-rendering을 하게 된다..
bool의 값을 변경했을 때 다시 렌더링을 하고 싶다면 아래와 같은 방법을 쓸 수 있다.
let list = [...this.arr];
list.splice(0, 1, {first: 1, bool: false});
this.arr = list;
위와 같이 할 경우 arr에 새로운 배열이 할당되어 arr이 가리키는 주소 값이 변경되므로 Vue는 변화를 감지하여 re-rendering을 하게 된다.
또는 아예 객체로 만들어버린다.
vuex
vuex: Vue.js의 상태 관리 라이브러리로 애플리케이션의 모든 컴포넌트에 대한 중앙 집중식 저 역할을 하며 의도적인 방법으로 상태를 변경 및 관리할 수 있다. Vuex는 기존 Flux의 아키텍처를 따라가고 있다. Vue.js에서도 react의 Redux를 사용할 수 있지만 Vue.js는 Vuex와의 호환이 좋을 뿐만 아니라 더 직관적으로 개발할 수 있다.
Vue 컴포넌트에서 data같은 개념으로, 원본 소스의 역할을 하며, View와 직접적으로 연결되어있는 Model이다. 이 state는 직접적인 변경은 불가능하고 mutation을 통해서만 변경이 가능하다. mutation을 통해 state가 변경이 일어나면 반응적으로 View가 업데이트된다.
mutations
Mutation은 state를 변경하는 유일한 방법이고 이벤트와 유사하다. mutation은 함수로 구현되며 첫 번째 인자는 state를 받을 수 있으며, 두 번째 인자는 payload를 받을 수 있다. 여기서 payload는 여러 필드를 포함할 수 있는 객체 형태도 가능하다. 이 mutation은 일반적으로(Helper를 쓰지 않는 경우)는 직접 호출을 할 수 없으며, commit을 통해서만 호출할 수 있다.
대부분 실무에서는 mutations에서는 API를 통해 전달받은 데이터의 가공하여 state를 설정하는 데 많이 사용된다고 한다.
store.commit('setData', payload)
action
Action은 mutation과 비슷하지만 mutation과는 달리 비동기 작업이 가능하다. 또한 mutation에 대한 commit이 가능하여 action에서도 mutation을 통해 state를 변경할 수 있다. action에서는 첫 번째 인자를 context 인자로 받을 수 있으며 이 context에는 state, commit, dispatch, rootstate와 같은 속성들을 포함한다. 두 번째 인자는 mutation과 동일하게 payload로 받을 수 있다.
commit을 통해 mutation을 호출했다면 Action은 dispatch를 통해서 호출한다. context의 속성을 보면 dispatch가 있는 것으로 보아 action에서는 서로 다른 action을 호출할 수 있다는 것을 볼 수 있다.
실무에서 actions은 Axios를 통한 API 호출과 그 결과에 대해서 반환(return)을 하거나 mutation으로 commit하여 상태를 변경하는 용도로 사용된다고 한다.
store.dispatch('setData', payload)
getters
Getters는 쉽게 Vue 컴포넌트에서 Computed로 볼 수 있다. 말로 풀자면 계산된 속성인데 getter의 결과는 종속성에 따라 캐시 되고 일부 종속성이 변경된 경우에만 다시 재계산된다. 즉, 특정 state에 대해 어떠한 연산을 하고 그 결과를 View에 바인딩할 수 있으며, state의 변경 여부에 따라 getter는 재계산이 되고 View 역시 업데이트를 일으킨다. 이때 state는 원본 데이터로서 변경이 일어나지 않는다.