Understanding the "this" keyword, call, apply, and bind in JavaScript - Lee-hyuna/33-js-concepts-kr GitHub Wiki

이건 우리 κ³ κΈ‰ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”μŠ€μ˜ μΌλΆ€μž…λ‹ˆλ‹€. 이 κ²Œμ‹œλ¬Όμ΄ λ§ˆμŒμ— λ“€λ©΄ ν™•μΈλ³΄μ„Έμš”.

μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ κ°€μž₯ μ˜€ν•΄ 된 λΆ€λΆ„ 쀑 ν•˜λ‚˜λŠ” this ν‚€μ›Œλ“œμž…λ‹ˆλ‹€. 이 κΈ€μ—μ„œλŠ” this ν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜κ³ μžˆλŠ” 것을 μ•Œμ•„λ‚΄λŠ” λ‹€μ„― 가지 κ·œμΉ™μ„ λ°°μ›λ‹ˆλ‹€. Implicit Binding, Explicit Binding, new binding, window binding, Lexical Binding. 이 κΈ°μˆ μ„ λ‹€λ£¨λŠ” λ°μžˆμ–΄ .call, .apply, .bind 및 new ν‚€μ›Œλ“œμ™€ 같은 μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ λ‹€λ₯Έ 뢀뢄도 λ°°μš°κ²Œλ©λ‹ˆλ‹€.

<iframe width="864" height="486" src="https://www.youtube.com/embed/zE9iro4r918" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ `this`ν‚€μ›Œλ“œμ˜ 세뢀사항을 μ‚΄νŽ΄λ³΄κΈ° 전에 ν•œ 걸음 λ¬ΌλŸ¬μ„œμ„œ `this`ν‚€μ›Œλ“œκ°€ μ™œ μ‘΄μž¬ν•˜λŠ”μ§€ λ¨Όμ € μ‚΄νŽ΄λ³΄λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€. `this`ν‚€μ›Œλ“œλŠ” μ„œλ‘œ λ‹€λ₯Έ μ»¨ν…μŠ€νŠΈλ‘œ ν•¨μˆ˜λ₯Ό μž¬μ‚¬μš© ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ‹€λ₯΄κ²Œ λ§ν•˜λ©΄, `this`ν‚€μ›Œλ“œλŠ” ν•¨μˆ˜ λ‚˜ λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•  λ•Œ μ–΄λ–€ 객체가 초점이 λ˜μ–΄μ•Όν•˜λŠ”μ§€ κ²°μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이 ν›„ μš°λ¦¬κ°€ μ΄μ•ΌκΈ°ν•˜λŠ” λͺ¨λ“  것은 κ·Έ 아이디어λ₯Ό λ°”νƒ•μœΌλ‘œ λ§Œλ“€μ–΄μ§ˆ κ²ƒμž…λ‹ˆλ‹€. μš°λ¦¬λŠ” λ‹€λ₯Έ μ»¨ν…μŠ€νŠΈ λ˜λŠ” λ‹€λ₯Έ κ°μ²΄μ—μ„œ ν•¨μˆ˜ λ‚˜ λ©”μ†Œλ“œλ₯Ό μž¬μ‚¬μš© ν•  수 있기λ₯Ό μ›ν•©λ‹ˆλ‹€.

κ°€μž₯ λ¨Όμ € μ‚΄νŽ΄λ³Ό 것은 thisν‚€μ›Œλ“œκ°€ 무엇을 μ°Έμ‘°ν•˜λŠ”μ§€ μ•Œλ €μ£ΌλŠ” κ²ƒμž…λ‹ˆλ‹€. 이 μ§ˆλ¬Έμ— λ‹΅ν•˜λ €κ³  ν•  λ•Œ μžμ‹ μ—κ²Œ κ°€μž₯ λ¨Όμ € 묻고 싢은 μ€‘μš”ν•œ μ§ˆλ¬Έμ€ β€˜μ΄ ν•¨μˆ˜λŠ” 어디에 ν˜ΈμΆœλ©λ‹ˆκΉŒ?’ μž…λ‹ˆλ‹€. thisν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜λŠ” 것을 μ•Œ 수 μžˆλŠ” μœ μΌν•œ 방법은 thisν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” ν•¨μˆ˜κ°€ 호좜 된 곳을 μ°ΎλŠ” κ²ƒμž…λ‹ˆλ‹€.

이미 μ΅μˆ™ν•œ 예둜 이것을 증λͺ…ν•˜κΈ° μœ„ν•΄, μš°λ¦¬κ°€ ν™˜μ˜ν•˜λŠ” λ©”μ‹œμ§€λ₯Ό μ•Œλ¦¬λŠ” 이름을 가진 greetν•¨μˆ˜λ₯Ό 가지고 μžˆλ‹€κ³  ν•©μ‹œλ‹€.

function greet (name) {
  alert(`Hello, my name is ${name}`)
}

greetκ°€ 무엇을 κ²½κ³  ν•  것인지 μ •ν™•ν•˜κ²Œ λ¬»λŠ”λ‹€λ©΄, λ‹Ήμ‹ μ˜ λŒ€λ‹΅μ€ λ¬΄μ—‡μž…λ‹ˆκΉŒ? ν•¨μˆ˜ μ •μ˜λ§Œ 주어진닀면 μ•Œ 수 μ—†μŠ΅λ‹ˆλ‹€. name이 무엇인지 μ•Œμ•„ 보렀면 greet의 ν•¨μˆ˜ ν˜ΈμΆœμ„ μ‚΄νŽ΄ λ΄μ•Όν•©λ‹ˆλ‹€.

greet('Tyler')

thisν‚€μ›Œλ“œκ°€ 무엇을 μ°Έμ‘°ν•˜κ³  μžˆλŠ”μ§€ μ•Œμ•„λ‚΄λŠ” 것도 μ •ν™•νžˆ 같은 μƒκ°μž…λ‹ˆλ‹€. thisν‚€μ›Œλ“œλŠ” ν•¨μˆ˜μ— λŒ€ν•œ 일반적인 인수처럼 생각할 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜λŠ” 방식에 따라 λ³€κ²½ 될 κ²ƒμž…λ‹ˆλ‹€.

이제 thisν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜λŠ” 것이 무엇인지 μ•Œμ•„λ‚΄λŠ” 첫 번째 λ‹¨κ³„λŠ” ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜λŠ” μœ„μΉ˜λ₯Ό ν™•μΈν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. λ‹€μŒ λ‹¨κ³„λŠ” λ¬΄μ—‡μž…λ‹ˆκΉŒ? λ‹€μŒ λ‹¨κ³„μ—μ„œ 우리λ₯Ό 돕기 μœ„ν•΄ 5가지 κ·œμΉ™μ΄λ‚˜ 지침을 μ •ν•  κ²ƒμž…λ‹ˆλ‹€.

  • Implicit Binding
  • Explicit Binding
  • new Binding
  • Lexical Binding
  • window Binding

Implicit Binding

μ—¬κΈ°μ„œ λͺ©ν‘œλŠ” thisν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ ν•¨μˆ˜ μ •μ˜λ₯Ό 보고 thisλ₯Ό μ°Έμ‘°ν•˜λŠ” 것을 말할 수 μžˆλŠ” κ²ƒμž…λ‹ˆλ‹€. 이λ₯Ό μœ„ν•œ 첫 번째이자 κ°€μž₯ 일반적인 κ·œμΉ™μ€ Implicit Binding이라고 λΆˆλ¦½λ‹ˆλ‹€. thisν‚€μ›Œλ“œκ°€ μ•½ 80%λ₯Ό μ°Έμ‘°ν•˜λŠ” 것이 무엇인지 말해 쀄 것이라고 λ‚˜λŠ” λ§ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€.

μ΄λ ‡κ²Œ 생긴 객체가 μžˆλ‹€κ³  ν•΄λ΄…μ‹œλ‹€.

const user = {
  name: 'Tyler',
  age: 27,
  greet() {
    alert(`Hello, my name is ${this.name}`)
  }
}

이제 user객체에 greetλ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λ €λ©΄ λ„νŠΈ ν‘œκΈ°λ²•μ„ μ‚¬μš©ν•΄μ•Όν•©λ‹ˆλ‹€.

user.greet()

이것은 우리λ₯Ό 'μ•”μ‹œ 적 바인딩'κ·œμΉ™μ˜ μ£Ό μš”μ μœΌλ‘œ μΈλ„ν•©λ‹ˆλ‹€. thisν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜κ³ μžˆλŠ” 것을 νŒŒμ•…ν•˜λ €λ©΄ λ¨Όμ € ν•¨μˆ˜κ°€ 호좜 될 λ•Œ 점의 μ™Όμͺ½μ„ λ³΄μ‹­μ‹œμ˜€. "점"μ΄μžˆλŠ” 경우 ν•΄λ‹Ή 점의 μ™Όμͺ½μ„보고 thisν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜λŠ” 객체λ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€.

μœ„μ˜ μ˜ˆμ—μ„œ userλŠ” '점'의 μ™Όμͺ½μœΌλ‘œ, thisν‚€μ›Œλ“œκ°€ user객체λ₯Ό μ°Έμ‘°ν•˜κ³  μžˆμŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€. λ”°λΌμ„œ greetλ©”μ†Œλ“œμ—μ„œ μžλ°”μŠ€ν¬λ¦½νŠΈ 인터프리터가 thisλ₯Ό user둜 λ³€κ²½ν•˜λŠ” κ²ƒμ²˜λŸΌ λ³΄μž…λ‹ˆλ‹€.

greet() {
  // alert(`Hello, my name is ${this.name}`)
  alert(`Hello, my name is ${user.name}`) // Tyler
}

λΉ„μŠ·ν•˜μ§€λ§Œ μ’€ 더 κ³ κΈ‰ 예λ₯Ό μ‚΄νŽ΄ λ³΄κ² μŠ΅λ‹ˆλ‹€. 이제name,age,greet property λŒ€μ‹ μ— user객체에nameκ³Όgreet propertyλ₯Ό 가진mother property을 λΆ€μ—¬ν•˜κ² μŠ΅λ‹ˆλ‹€.

const user = {
  name: 'Tyler',
  age: 27,
  greet() {
    alert(`Hello, my name is ${this.name}`)
  },
  mother: {
    name: 'Stacey',
    greet() {
      alert(`Hello, my name is ${this.name}`)
    }
  }
}

이제 μ§ˆλ¬Έμ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€. μ•„λž˜μ— μžˆλŠ” 각각의 ν˜ΈμΆœμ€ 무엇을 κ²½κ³ ν•  것인가?

user.greet()
user.mother.greet()

this ν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜λŠ” 것을 μ•Œμ•„ λ‚΄λ €κ³  ν•  λ•Œλ§ˆλ‹€ ν˜ΈμΆœμ„λ³΄κ³  "점의 μ™Όμͺ½"에 무엇이 μžˆλŠ”μ§€ μ•Œμ•„μ•Όν•©λ‹ˆλ‹€. 첫 번째 ν˜ΈμΆœμ—μ„œ userλŠ” 점의 μ™Όμͺ½μ— 있으며 thisλŠ” userλ₯Ό μ°Έμ‘° ν•  κ²ƒμž„μ„ μ˜λ―Έν•©λ‹ˆλ‹€. 두 번째 ν˜ΈμΆœμ—μ„œ motherλŠ” 점의 μ™Όμͺ½μ—μžˆλŠ” 것이고 thisλŠ” motherλ₯Ό λ‚˜νƒ€λ‚Ό κ²ƒμž„μ„ μ˜λ―Έν•©λ‹ˆλ‹€.

user.greet() // Tyler
user.mother.greet() // Stacey

μ•žμ—μ„œ μ–ΈκΈ‰ν–ˆλ“―μ΄, μ•½ 80%λŠ” "점의 μ™Όμͺ½"에 λŒ€μƒμ΄μžˆμ„ κ²ƒμž…λ‹ˆλ‹€. κ·Έλž˜μ„œ thisν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜κ³ μžˆλŠ” 것을 μ•Œμ•„λ‚Ό λ•Œ 첫 번째 λ‹¨κ³„λŠ” "점의 μ™Όμͺ½μ„ λ³΄λŠ” 것"μž…λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜, 점이 μ—†λ‹€λ©΄ μ–΄λ–¨κΉŒμš”? 이것은 우리λ₯Ό λ‹€μŒ κ·œμΉ™μœΌλ‘œ μΈλ„ν•©λ‹ˆλ‹€.

Explicit Binding

자,greetν•¨μˆ˜ λŒ€μ‹ μ— user객체에 λŒ€ν•œ λ©”μ†Œλ“œκ°€ μžˆλ‹€λ©΄ 그것은 단지 λ…μžμ μΈ 독립 ν•¨μˆ˜ μ˜€μ„ κ²ƒμž…λ‹ˆλ‹€.

function greet () {
  alert(`Hello, my name is ${this.name}`)
}

const user = {
  name: 'Tyler',
  age: 27,
}

μš°λ¦¬λŠ”thisν‚€μ›Œλ“œκ°€ 무엇을 가리킀고 μžˆλŠ”μ§€ μ•ŒκΈ° μœ„ν•΄ λ¨Όμ € ν•¨μˆ˜κ°€ μ–΄λ””μ—μ„œ ν˜ΈμΆœλ˜λŠ”μ§€ μ‚΄νŽ΄ λ΄μ•Όν•©λ‹ˆλ‹€. 이제, greetλ₯Ό μ–΄λ–»κ²Œ 호좜 ν•  수 μžˆμŠ΅λ‹ˆκΉŒ? user객체λ₯Ό μ°Έμ‘°ν•˜λŠ” thisν‚€μ›Œλ“œλ‘œ μ–΄λ–»κ²Œ 호좜 ν•  수 μžˆμŠ΅λ‹ˆκΉŒ? userλŠ” greetλ©”μ†Œλ“œλ₯Ό 가지고 μžˆμ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μ΄μ „μ²˜λŸΌ user.greet()λ₯Ό ν•  수 μ—†μŠ΅λ‹ˆλ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ λͺ¨λ“  ν•¨μˆ˜λŠ” μ—¬λŸ¬λΆ„μ΄ μ •ν™•ν•˜κ²Œ 이것을 ν•  수있게 ν•΄μ£ΌλŠ” λ©”μ†Œλ“œλ₯Ό ν¬ν•¨ν•˜κ³  있으며 κ·Έ λ©”μ†Œλ“œμ˜ 이름은 callμž…λ‹ˆλ‹€.

"call"은 호좜 될 μ»¨ν…μŠ€νŠΈλ₯Ό μ§€μ •ν•˜λŠ” ν•¨μˆ˜λ₯Ό 호좜 ν•  수있게 ν•˜λŠ” λͺ¨λ“  ν•¨μˆ˜μ˜ λ©”μ†Œλ“œμž…λ‹ˆλ‹€. 

이λ₯Ό 염두해 두고 λ‹€μŒ μ½”λ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ user μ»¨ν…μŠ€νŠΈμ—μ„œ greet을 호좜 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

greet.call(user)

λ‹€μ‹œ λ§ν•˜μ§€λ§Œ,call은 λͺ¨λ“  ν•¨μˆ˜μ˜ 속성이고, 당신이 μ „λ‹¬ν•˜λŠ” 첫 번째 μΈμžλŠ” ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜λŠ” μ»¨ν…μŠ€νŠΈ (λ˜λŠ” 초점 객체)κ°€ 될 κ²ƒμž…λ‹ˆλ‹€. 즉, ν˜ΈμΆœν•˜κΈ° μœ„ν•΄ μ „λ‹¬ν•˜λŠ” 첫 번째 μΈμˆ˜λŠ” ν•΄λ‹Ή ν•¨μˆ˜ λ‚΄λΆ€μ˜ thisν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

μš°λ¦¬κ°€ λͺ…μ‹œ 적으둜 (.call을 μ‚¬μš©ν•˜κ³  있기 λ•Œλ¬Έμ—) thisν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜κ³ μžˆλŠ” 것을 μ§€μ •ν•˜κΈ° λ•Œλ¬Έμ— 이것이 κ·œμΉ™ #2 (Explicit Binding)의 κΈ°μ΄ˆμž…λ‹ˆλ‹€.

이제, β€˜greet’ function을 쑰금 μˆ˜μ •ν•΄λ΄…μ‹œλ‹€. λ§Œμ•½ μš°λ¦¬κ°€ λͺ‡ 개의 객체λ₯Ό μ „λ‹¬ν•œλ‹€κ³  κ°€μ •ν•΄λ³Έλ‹€λ©΄ μ–΄λ–»κ²Œ λ κΉŒμš”? κ·Έλ“€μ˜ 이름을 가지고, μš°λ¦¬λŠ” λ˜ν•œ 그듀이 μ•„λŠ” μ–Έμ–΄λ‘œ μ•Œλ €μ£ΌκΈ°λ₯Ό μ›ν–ˆμŠ΅λ‹ˆλ‹€ μ•„λž˜μ™€ 같이 λ§μž…λ‹ˆλ‹€.

function greet (l1, l2, l3) {
  alert(
    `Hello, my name is ${this.name} and I know ${l1}, ${l2}, and ${l3}`
  )
}

이제 .call을 μ‚¬μš©ν•˜μ—¬ ν˜ΈμΆœλ˜λŠ” ν•¨μˆ˜μ— 인수λ₯Ό μ „λ‹¬ν•˜κΈ° μœ„ν•΄ 첫 번째 인수λ₯Ό λ¬Έλ§₯으둜 μ§€μ •ν•œ 후에 ν•˜λ‚˜μ”© μ „λ‹¬ν•©λ‹ˆλ‹€.

function greet (l1, l2, l3) {
  alert(
    `Hello, my name is ${this.name} and I know ${l1}, ${l2}, and ${l3}`
  )
}

const user = {
  name: 'Tyler',
  age: 27,
}

const languages = ['JavaScript', 'Ruby', 'Python']

greet.call(user, languages[0], languages[1], languages[2])

이것은 νš¨κ³Όκ°€ 있으며 .call을 μ‚¬μš©ν•˜μ—¬ ν˜ΈμΆœλ˜λŠ” ν•¨μˆ˜μ— 인수λ₯Ό μ „λ‹¬ν•˜λŠ” 방법을 λ³΄μ—¬μ€λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ μ—¬λŸ¬λΆ„μ΄ λˆˆμΉ˜μ±˜μ„μ§€ λͺ¨λ₯΄κ² μ§€λ§Œ, 우리의 languagesλ°°μ—΄μ—μ„œ ν•˜λ‚˜μ”© 인자λ₯Ό μ „λ‹¬ν•΄μ•Όν•˜λŠ” 것은 μ§œμ¦λ‚˜λŠ” μΌμž…λ‹ˆλ‹€. 전체 배열을 두 번째 인수둜 전달할 수 있으면 μžλ°”μŠ€ν¬λ¦½νŠΈκ°€ 이λ₯Ό ν™•μ‚°μ‹œν‚¬ 수 μžˆλ‹€λ©΄ 쒋을 κ²ƒμž…λ‹ˆλ‹€. μš°λ¦¬μ—κ²Œ 쒋은 μ†Œμ‹μž…λ‹ˆλ‹€. 이것은 μ •ν™•νžˆ .applyκ°€ ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. .applyλŠ” .callκ³Ό μ™„μ „νžˆ λ˜‘κ°™μ§€λ§Œ 인수 ν•˜λ‚˜ ν•˜λ‚˜λ₯Ό μ „λ‹¬ν•˜λŠ” λŒ€μ‹ μ— ν•˜λ‚˜μ˜ 배열을 전달할 수 있으며 λ°°μ—΄μ˜ 각 μš”μ†Œλ₯Ό ν•¨μˆ˜μ˜ 인자둜 μ „λ‹¬ν•©λ‹ˆλ‹€.

κ·Έλž˜μ„œ μ΄μ œλŠ” .applyλ₯Ό μ‚¬μš©ν•˜λ©΄, 우리의 μ½”λ“œλŠ” λ‹€λ₯Έ 것듀이 κ·ΈλŒ€λ‘œ μœ μ§€λ˜λ©΄μ„œ (μ•„λž˜)μ½”λ“œλ‘œ λ°”λ€” 수 μžˆμŠ΅λ‹ˆλ‹€.

const languages = ['JavaScript', 'Ruby', 'Python']

// greet.call(user, languages[0], languages[1], languages[2])
greet.apply(user, languages)

μ§€κΈˆκΉŒμ§€ "Explicit Binding"κ·œμΉ™μ— 따라 .callκ³Ό .apply에 λŒ€ν•΄ λ°°μ› μŠ΅λ‹ˆλ‹€. λ‘˜ λ‹€ ν•¨μˆ˜ ν˜ΈμΆœμ„ ν—ˆμš©ν•˜κ³ , thisν‚€μ›Œλ“œκ°€ κ·Έ λ‚΄λΆ€μ—μ„œ μ°Έμ‘° ν•  κ²ƒμž„μ„ μ§€μ •ν•©λ‹ˆλ‹€. 이 κ·œμΉ™μ˜ λ§ˆμ§€λ§‰ 뢀뢄은.bindμž…λ‹ˆλ‹€. .bindλŠ” .callκ³Ό λ˜‘κ°™μ§€ 만 μ¦‰μ‹œ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λŠ” λŒ€μ‹  λ‚˜μ€‘μ— 호좜 ν•  μˆ˜μžˆλŠ” μƒˆλ‘œμš΄ ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. κ·Έλž˜μ„œ μ΄μ „μ½”λ“œμ— .bindλ₯Ό μ‚¬μš©ν•˜μ—¬ μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³΄λ©΄ λ‹€μŒκ³Ό 같이 보일 κ²ƒμž…λ‹ˆλ‹€.

function greet (l1, l2, l3) {
  alert(
    `Hello, my name is ${this.name} and I know ${l1}, ${l2}, and ${l3}`
  )
}

const user = {
  name: 'Tyler',
  age: 27,
}

const languages = ['JavaScript', 'Ruby', 'Python']

const newFn = greet.bind(user, languages[0], languages[1], languages[2])
newFn() // alerts "Hello, my name is Tyler and I know JavaScript, Ruby, and Python"

new Binding

thisν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜κ³ μžˆλŠ” 것을 μ•Œμ•„λ‚΄λŠ” μ„Έ 번째 κ·œμΉ™μ€ new Bindingμž…λ‹ˆλ‹€. λ§Œμ•½ newν‚€μ›Œλ“œμ™€ ν•¨κ»˜ ν•¨μˆ˜ ν˜ΈμΆœμ„ ν•  λ•Œλ§ˆλ‹€ 당신이 μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ newν‚€μ›Œλ“œμ— μ΅μˆ™ν•˜μ§€ μ•Šλ‹€λ©΄, μžλ°”μŠ€ν¬λ¦½νŠΈ μΈν„°ν”„λ¦¬ν„°λŠ” 당신을 μœ„ν•œ this라 λΆˆλ¦¬λŠ” μƒˆλ‘œμš΄ 객체λ₯Ό 생성할 κ²ƒμž…λ‹ˆλ‹€. κ·ΈλŸ¬λ―€λ‘œ μžμ—°μŠ€λŸ½κ²Œ, new와 ν•¨κ»˜ ν•¨μˆ˜κ°€ ν˜ΈμΆœλœλ‹€λ©΄, 이 thisν‚€μ›Œλ“œλŠ” 인터프리터가 λ§Œλ“  μƒˆλ‘œμš΄ 객체λ₯Ό μ°Έμ‘°ν•©λ‹ˆλ‹€.

function User (name, age) {
  /*
    Under the hood, JavaScript creates a new object called `this`
    which delegates to the User's prototype on failed lookups. If a
    function is called with the new keyword, then it's this new object
    that interpretor created that the this keyword is referencing.
  */

  this.name = name
  this.age = age
}

const me = new User('Tyler', 27)

Lexical Binding

이 μ‹œμ μ—μ„œ μš°λ¦¬λŠ” 4번째 κ·œμΉ™μ„ λ”°λ₯΄κ³  있으며 μ•½κ°„ 압도 λ‹Ήν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. 그건 κ³΅ν‰ν•©λ‹ˆλ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ thisν‚€μ›Œλ“œλŠ” 틀림없이 더 볡작 ν•  κ²ƒμž…λ‹ˆλ‹€. 쒋은 μ†Œμ‹μ€ λ‹€μŒ κ·œμΉ™μ΄ κ°€μž₯ 직관적인 κ²ƒμž…λ‹ˆλ‹€.

당신이 전에 λ“€μ–΄λ³Έ 적이 있고 arrow function을 μ‚¬μš©ν–ˆμ„ κ°€λŠ₯성이 μžˆλ‹€. ES6의 μƒˆλ‘œμš΄ κ²ƒμž…λ‹ˆλ‹€. 이 ν•¨μˆ˜λŠ” 당신이 더 κ°„κ²°ν•œ ν˜•μ‹μœΌλ‘œ ν•¨μˆ˜λ₯Ό μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

friends.map((friend) => friend.name)

간결함보닀 arrow functionλŠ” thisν‚€μ›Œλ“œμ— κ΄€ν•΄μ„œ 훨씬 더 직관적인 접근법을 κ°€μ§€κ³ μžˆλ‹€. arrow function은 일반 ν•¨μˆ˜μ™€ 달리 thisκ°€ μ—†μŠ΅λ‹ˆλ‹€. λŒ€μ‹  thisλŠ” lexically둜 κ²°μ •λ©λ‹ˆλ‹€.
μ΄λŠ” 정상적인 λ³€μˆ˜ 쑰회 κ·œμΉ™μ„ 따라 μ–΄λ–»κ²Œ μ˜ˆμƒν• μ§€ κ²°μ •λ˜λŠ” 멋진 λ°©μ‹μž…λ‹ˆλ‹€. μ•žμ„œ μ‚¬μš©ν–ˆλ˜ μ˜ˆμ‹œλ₯Ό κ³„μ†ν•΄λ΄…μ‹œλ‹€. 이제, language와greet을 객체와 λΆ„λ¦¬ν•˜μ—¬ μ‚¬μš©ν•˜μ§€ μ•Šκ³  κ²°ν•©ν•΄ λ΄…μ‹œλ‹€.

const user = {
  name: 'Tyler',
  age: 27,
  languages: ['JavaScript', 'Ruby', 'Python'],
  greet() {}
}

μ•žμ—μ„œ μš°λ¦¬λŠ” languagesλ°°μ—΄μ˜ 길이가 항상 3이라고 κ°€μ •ν–ˆμŠ΅λ‹ˆλ‹€. κ·Έλ ‡κ²Œν•¨μœΌλ‘œμ¨, μš°λ¦¬λŠ”l1,l2,l3κ³Ό 같은 ν•˜λ“œμ½”λ“œλœ λ³€μˆ˜λ₯Ό μ‚¬μš©ν•  수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. greetλ₯Ό 쑰금 더 ν˜„λͺ…ν•˜κ²Œ λ§Œλ“€κ³  languagesκ°€ μ–΄λ–€ 길이라도 될 수 μžˆλ‹€κ³  κ°€μ •ν•©μ‹œλ‹€. μ΄λ ‡κ²Œν•˜κΈ° μœ„ν•΄ μš°λ¦¬λŠ” λ¬Έμžμ—΄μ„ λ§Œλ“€κΈ° μœ„ν•΄ .reduceλ₯Ό μ‚¬μš©ν•  κ²ƒμž…λ‹ˆλ‹€.

const user = {
  name: 'Tyler',
  age: 27,
  languages: ['JavaScript', 'Ruby', 'Python'],
  greet(){
    const hello = `Hello, my name is ${this.name} and I know`
    const langs = this.languages.reduce(function(str, lang, i){
      if (i === this.languages.length - 1) {
        return `${str} and ${lang}.`
      }
      return `${str} ${lang},`
    }, '')
    alert(hello + langs)
  }
}

훨씬 더 λ§Žμ€ μ½”λ“œμ§€λ§Œ μ΅œμ’… κ²°κ³ΌλŠ” κ°™μ•„μ•Ό ν•©λ‹ˆλ‹€. μš°λ¦¬κ°€user.greet()λ₯Ό 호좜 ν•  λ•Œ Hello, my name is Tyler and I know JavaScript, Ruby, and Python..라고 κΈ°λŒ€ν•  κ²ƒμž…λ‹ˆλ‹€. μŠ¬ν”„κ²Œλ„ 였λ₯˜κ°€ μžˆμŠ΅λ‹ˆλ‹€. 그것을 발견 ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?
μœ„μ˜ μ½”λ“œλ₯Ό 작고 μ½˜μ†”μ—μ„œ μ‹€ν–‰ν•˜μ‹­μ‹œμ˜€. Uncaught TypeError: Cannot read property 'length' of undefined 였λ₯˜κ°€ λ°œμƒν•˜λŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€. .lengthλ₯Ό μ‚¬μš©ν•˜λŠ” μœ μΌν•œ 곳은 9λ²ˆμ€„μ— μžˆμœΌλ―€λ‘œ μš°λ¦¬λŠ” 우리의 였λ₯˜κ°€ μžˆλ‹€λŠ” 것을 μ••λ‹ˆλ‹€.

if (i === this.languages.length - 1) {}

우리의 잘λͺ»μ— λ”°λ₯΄λ©΄,this.langaugesλŠ” μ •μ˜λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. thisν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜λŠ”κ²Œ 무엇인지 λΆ„λͺ…νžˆ λ°ν˜€ λ‚΄κΈ° μœ„ν•΄ userλ₯Ό μ°Έμ‘°ν•˜μ§€ μ•ŠλŠ” 단계λ₯Ό μ°Ύμ•„ λ³΄κ² μŠ΅λ‹ˆλ‹€. λ¨Όμ € ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜λŠ” μœ„μΉ˜λ₯Ό μ‚΄νŽ΄λ³Ό ν•„μš”κ°€ μžˆμŠ΅λ‹ˆλ‹€. ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜λŠ” μœ„μΉ˜λŠ” μ–΄λ””μž…λ‹ˆκΉŒ? 이 ν•¨μˆ˜λŠ”.reduce에 μ „λ‹¬λ˜μ–΄μ„œ μš°λ¦¬λŠ” μ „ν˜€ λͺ¨λ¦…λ‹ˆλ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” .reduceκ΅¬ν˜„μ—μ„œ κ·Έ 자체둜 λ™μž‘ν•˜κΈ° λ•Œλ¬Έμ— μš°λ¦¬λŠ” 읡λͺ…μ˜ ν•¨μˆ˜ ν˜ΈμΆœμ„ μ‹€μ œλ‘œ 보지 λͺ»ν•©λ‹ˆλ‹€. 그게 λ¬Έμ œμž…λ‹ˆλ‹€. μš°λ¦¬λŠ”.reduce에 전달 된 읡λͺ…μ˜ ν•¨μˆ˜κ°€ userμ»¨ν…μŠ€νŠΈμ—μ„œ ν˜ΈμΆœλ˜λ„λ‘ μ§€μ •ν•΄μ•Όν•©λ‹ˆλ‹€. κ·Έλ ‡κ²Œν•˜λ©΄ this.languagesλŠ” user.languagesλ₯Ό μ°Έμ‘° ν•  κ²ƒμž…λ‹ˆλ‹€. μœ„μ—μ„œ 배운 κ²ƒμ²˜λŸΌ .bindλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

const user = {
  name: 'Tyler',
  age: 27,
  languages: ['JavaScript', 'Ruby', 'Python'],
  greet() {
    const hello = `Hello, my name is ${this.name} and I know`

    const langs = this.languages.reduce(function (str, lang, i) {
      if (i === this.languages.length - 1) {
        return `${str} and ${lang}.`
      }

      return `${str} ${lang},`
    }.bind(this), "")

    alert(hello + langs)
  }
}

κ·Έλž˜μ„œ μš°λ¦¬λŠ” .bindκ°€ μ–΄λ–»κ²Œ 이 문제λ₯Ό ν•΄κ²°ν•˜λŠ”μ§€λ₯Ό λ³΄μ•˜μœΌλ©°, 이것이 arrow function와 μ–΄λ–€ 관련이 μžˆλŠ”μ§€λ₯Ό λ³΄μ•˜μŠ΅λ‹ˆλ‹€. μ•žμ„œ arrow function둜 "thisκ°€ lexically둜 κ²°μ •λ˜μ—ˆμŠ΅λ‹ˆλ‹€. 이것은 정상적인 λ³€μˆ˜ 쑰회 κ·œμΉ™μ— 따라 thisκ°€ μ–΄λ–»κ²Œ κΈ°λŒ€λ˜λŠ”μ§€ κ²°μ •ν•˜λŠ” 멋진 λ°©λ²•μž…λ‹ˆλ‹€. "

μœ„μ˜ μ½”λ“œμ—μ„œ μžμ—°μŠ€λŸ¬μš΄ 직감에 따라 읡λͺ… ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ thisν‚€μ›Œλ“œ μ°Έμ‘°λŠ” 무엇을 μ˜λ―Έν•©λ‹ˆκΉŒ? λ‚˜μ—κ²ŒλŠ” userλ₯Ό μ°Έμ‘°ν•΄μ•Ό ν•©λ‹ˆλ‹€. .reduce에 μƒˆλ‘œμš΄ ν•¨μˆ˜λ₯Ό μ „λ‹¬ν•΄μ•Όλ§Œν–ˆκΈ° λ•Œλ¬Έμ— μƒˆλ‘œμš΄ μ»¨ν…μŠ€νŠΈλ₯Ό λ§Œλ“€ μ΄μœ κ°€ μ—†μŠ΅λ‹ˆλ‹€. 그리고 κ·Έ 직감으둜 arrow function의 κ°€μΉ˜λ₯Ό μ’…μ’… κ°„κ³Όν•©λ‹ˆλ‹€. μœ„μ˜ μ½”λ“œλ₯Ό λ‹€μ‹œ μž‘μ„±ν•˜κ³  읡λͺ…μ˜ ν•¨μˆ˜ μ„ μ–Έ λŒ€μ‹  읡λͺ…μ˜ arrow functionλ₯Ό μ‚¬μš©ν•˜λ©΄ λͺ¨λ“  것이 "잘 μž‘λ™ν•©λ‹ˆλ‹€".

const user = {
  name: 'Tyler',
  age: 27,
  languages: ['JavaScript', 'Ruby', 'Python'],
  greet() {
    const hello = `Hello, my name is ${this.name} and I know`

    const langs = this.languages.reduce((str, lang, i) => {
      if (i === this.languages.length - 1) {
        return `${str} and ${lang}.`
      }

      return `${str} ${lang},`
    }, "")

    alert(hello + langs)
  }
}

arrow function으둜 인해 thisκ°€ lexically둜 κ²°μ •λœλ‹€λŠ” μ΄μœ λ„ λ‹€μ‹œ ν•œλ²ˆ μ œκΈ°λ©λ‹ˆλ‹€. arrow functionμ—λŠ” thisκ°€ μ—†μŠ΅λ‹ˆλ‹€. λŒ€μ‹  λ³€μˆ˜ μ‘°νšŒμ™€ λ§ˆμ°¬κ°€μ§€λ‘œ μžλ°”μŠ€ν¬λ¦½νŠΈ μΈν„°ν”„λ¦¬ν„°λŠ” thisκ°€ μ°Έμ‘°ν•˜λŠ” 것을 νŒλ³„ν•˜κΈ° μœ„ν•΄ λ‘˜λŸ¬μ‹ΈλŠ” (λΆ€λͺ¨)λ²”μœ„λ₯Ό μ‘°μ‚¬ν•©λ‹ˆλ‹€.

window Binding

λ§ˆμ§€λ§‰μœΌλ‘œ "catch-all"의 경우 인 window Bindingμž…λ‹ˆλ‹€. λ‹€μŒ μ½”λ“œκ°€ μžˆλ‹€κ³  κ°€μ • ν•΄ λ΄…μ‹œλ‹€.

function sayAge () {
  console.log(`My age is ${this.age}`)
}

const user = {
  name: 'Tyler',
  age: 27
}

μ•žμ—μ„œ λ‹€λ€˜λ˜ κ²ƒμ²˜λŸΌ,sayAgeλ₯Ό userμ»¨ν…μŠ€νŠΈμ—μ„œ ν˜ΈμΆœν•˜κ³  μ‹Άλ‹€λ©΄ .call, .apply λ˜λŠ” .bindλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μš°λ¦¬κ°€ κ·Έ 쀑 ν•˜λ‚˜λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³  ν‰μ†Œμ²˜λŸΌ sayAgeλ₯Ό ν˜ΈμΆœν•˜λ©΄ μ–΄λ–»κ²Œ λ κΉŒμš”?

sayAge() // My age is undefined

this.ageκ°€ μ •μ˜λ˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— 당신이 μ–»λŠ” 것은 λ†€λžμ§€λ„ μ•Šμ§€λ§Œ, My age is undefinedμž…λ‹ˆλ‹€. μ—¬κΈ°κ°€ μ’€ μ΄μƒν•œ 점이 μžˆμŠ΅λ‹ˆλ‹€. μ—¬κΈ°μ—μ„œ μ‹€μ œλ‘œ μΌμ–΄λ‚˜κ³ μžˆλŠ” 것은 점의 μ™Όμͺ½μ— 아무것도 μ—†κΈ° λ•Œλ¬Έμ— .call, .apply, .bind λ˜λŠ” new ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” window객체λ₯Ό μ°Έμ‘°ν•˜κΈ° μœ„ν•΄ thisλ₯Ό 기본으둜 ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 즉, window객체에 age propertyλ₯Ό μΆ”κ°€ν•˜λ©΄ sayAgeν•¨μˆ˜λ₯Ό λ‹€μ‹œ 호좜 ν•  λ•Œ this.ageλŠ” 더 이상 μ •μ˜λ˜μ§€ μ•Šμ§€λ§Œ λŒ€μ‹  age propertyλŠ” window객체에 μžˆμŠ΅λ‹ˆλ‹€. λ‚  믿지 μ•Šλ‹ˆ? 이 μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜μ‹­μ‹œμ˜€.

window.age = 27

function sayAge () {
  console.log(`My age is ${this.age}`)
}

κ½€ 귀엽지? 이것이 λ°”λ‘œ 5번째 κ·œμΉ™μΈ window Bindingμ΄λΌλŠ” μ΄μœ μž…λ‹ˆλ‹€. λ‹€λ₯Έ κ·œμΉ™λ“€ 쀑 μ–΄λŠ 것도 μΆ©μ‘±λ˜μ§€ μ•ŠμœΌλ©΄ μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” window객체λ₯Ό μ°Έμ‘°ν•˜κΈ° μœ„ν•΄ thisν‚€μ›Œλ“œλ₯Ό κΈ°λ³Έκ°’μœΌλ‘œ μ‚¬μš©ν•©λ‹ˆλ‹€.

ES5μ—μ„œ "strict mode"κ°€ ν™œμ„±ν™” 된 경우 μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” μ˜¬λ°”λ₯Έ μž‘μ—…μ„ μˆ˜ν–‰ν•˜κ³  window객체λ₯Ό κΈ°λ³Έκ°’μœΌλ‘œ μ„€μ •ν•˜λŠ” λŒ€μ‹  "this"λ₯Ό undefined μƒνƒœλ‘œ μœ μ§€ν•©λ‹ˆλ‹€.
'use strict'

window.age = 27

function sayAge () {
  console.log(`My age is ${this.age}`)
}

sayAge() // TypeError: Cannot read property 'age' of undefined

λ”°λΌμ„œ λͺ¨λ“  κ·œμΉ™μ„ μ‹€μ œλ‘œ μ μš©ν•˜λ©΄ ν•¨μˆ˜ 내뢀에 thisν‚€μ›Œλ“œκ°€ ν‘œμ‹œ 될 λ•Œλ§ˆλ‹€ μ΄λŸ¬ν•œ ν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜λŠ” ν•­λͺ©μ„ νŒŒμ•…ν•˜κΈ° μœ„ν•΄ μˆ˜ν–‰ν•΄μ•Όν•˜λŠ” λ‹¨κ³„μž…λ‹ˆλ‹€.

  1. ν•¨μˆ˜ 호좜이 μ–΄λ””μ„œ μΌμ–΄λ‚¬λŠ”μ§€ ν™•μΈν•œλ‹€.
  2. 점을 κΈ°μ€€μœΌλ‘œ μ™Όμͺ½μ— 객체가 μžˆλŠ”μ§€ ν™•μΈν•˜κ³ , 그것이 μžˆλ‹€λ©΄ 그게 λ°”λ‘œ thisν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜λŠ” 것이닀. λ§Œμ•½μ— μ—†λ‹€λ©΄ 3번으둜 가라.
  3. β€œcall”, β€œapply”, ν˜Ήμ€ β€œbind”와 ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜μ—ˆλŠ”κ°€? λ§Œμ•½μ— κ·Έλ ‡λ‹€λ©΄ thisν‚€μ›Œλ“œκ°€ μ°Έμ‘°ν•˜λŠ” 것을 λͺ…μ‹œμ μœΌλ‘œ μ„ μ–Έν•  것이닀. 그렇지 μ•Šλ‹€λ©΄ 4번으둜 가라
  4. ν•¨μˆ˜κ°€ new ν‚€μ›Œλ“œμ™€ 호좜이 λ˜μ—ˆλŠ”κ°€? κ·Έλ ‡λ‹€λ©΄, thisν‚€μ›Œλ“œλŠ” μƒˆλ‘­κ²Œ 창쑰된 객체고 μžλ°”μŠ€ν¬λ¦½νŠΈ 인터프리터에 μ˜ν•΄ μƒμ„±λœ 것이닀. 이것듀과 호좜된 게 μ•„λ‹ˆλΌλ©΄ 5번으둜 가라.
  5. ν™”μ‚΄ν‘œ ν•¨μˆ˜ μ•ˆμ— thisκ°€ μžˆλŠ”κ°€? κ·Έλ ‡λ‹€λ©΄ μ•„λ§ˆλ„ 근처의 (λΆ€λͺ¨)μŠ€μ½”ν”„μ—μ„œ Lexically - μ–΄νœ˜μ μœΌλ‘œ? - 찾을 수 μžˆμ„ 것이닀. 그렇지 μ•Šλ‹€λ©΄ 6번으둜 가라.
  6. Strict modeλ₯Ό μ‚¬μš©μ€‘μΈκ°€? κ·Έλ ‡λ‹€λ©΄ thisν‚€μ›Œλ“œλŠ” undefined이닀. 그렇지 μ•Šλ‹€λ©΄ 7번으둜 가라.
  7. μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” μ΄μƒν•œ μ• λ‹€. thisλŠ” window 객체λ₯Ό μ°Έμ‘°ν•œλ‹€.
⚠️ **GitHub.com Fallback** ⚠️