호출, 적용 및 바인딩에 대한 자세한 설명
배경
이게 뭐야
앞에서 배운 JS 프로토타입 체인에서 js의 모든 함수는 Function의 인스턴스이고 Function의 프로토타입 객체(Function.prototype)에는 call, apply 및 bind 메서드를 포함하여 많은 속성과 메서드가 있음을 알 수 있습니다.
프로토타입의 규칙에 따라 모든 함수는 프로토타입의 속성과 메서드를 사용할 수 있으므로 모든 함수와 함수만 호출, 적용 및 바인딩 메서드를 사용할 수 있습니다.
뭐하세요?
그들의 기능은 한 문장으로 설명될 수 있습니다: 이것의 방향을 바꾸는 것입니다.
call(), apply(), bind()의 차이점
같은:
- 둘 다 대상 함수가 실행될 때 내부 this 포인터를 변경할 수 있습니다.
- 메서드의 첫 번째 매개변수는 함수가 실행될 때 this의 내부 값을 지정하는 데 사용됩니다.
- 대상 함수에 매개 변수를 얼마든지 전달하도록 지원
- 메서드의 첫 번째 매개 변수에 값이 전달되지 않거나 undefined 및 null이 전달되면 JavaScript 일반 모드에서 대상 함수 내부의 this는 window 개체를 가리키고 엄격 모드에서는 각각 undefined 및 null을 가리킵니다.
다른:
- apply() 메소드는 두 개의 매개변수를 수신할 수 있는 반면 call() 및 bind() 메소드는 여러 매개변수를 수신할 수 있습니다.
- apply() 메서드가 대상 함수에 매개변수를 전달할 때 메서드의 두 번째 매개변수로 매개변수 배열 또는 인수 객체만 사용하면 되지만 call() 및 bind() 메서드는 전달된 매개변수를 나열해야 합니다. 메서드의 매개변수를 하나씩 하나씩.
- call() 및 apply() 메서드가 호출되면 대상 함수가 즉시 실행되지만 bind() 메서드는 그렇지 않고 새 함수(대상 함수의 복사본)를 반환하며 함수 내부의 this는 함수를 가리킵니다. 첫 번째 One 매개변수에 추가한 후 새 기능을 실행하는 것은 대상 기능을 실행하는 것과 동일합니다.
- bind() 메서드만 함수 커링을 구현하므로 대상 함수에 매개 변수를 두 번 전달할 수 있습니다.
call() 및 수동 모의 구현
call() 메소드
call() 메서드를 호출하면 대상 함수가 즉시 실행되고 동시에 함수 내에서 this의 포인터가 변경됩니다. 이 지점은 메서드의 첫 번째 매개변수에 의해 결정되며, 나중에 하나씩 나열된 모든 매개변수는 대상 함수의 매개변수로 하나씩 전달됩니다.
let obj = {
name:"胡歌",
sum(a, b) {
console.log(this.name)
return a + b
}
}
let obj1 = {
name:"李逍遥"
}
obj.sum.call(obj1, 1, 2) // 李逍遥 3
/* 正常模式 */
obj.sum.call() // window
obj.sum.call(undefined, 1, 2) // window
obj.sum.call(null, 1, 2) // window
/* 严格模式 */
'use strict'
obj.sum.call() // undefined
obj.sum.call(undefined, 1, 2) // undefined
obj.sum.call(null, 1, 2) // null
수동 모의 구현
설계 논리:
- myCall() 메서드는 Function 프로토타입 개체에 추가되며, 대상 함수가 이 메서드를 호출하면 myCall() 메서드 내부의 this가 대상 함수를 가리킵니다.
- 컨텍스트 개체의 메서드로 대상 함수를 실행하여 대상 함수 내부의 this가 컨텍스트 개체를 가리킬 것입니다.
- 컨텍스트 개체에서 대상 함수를 제거합니다.
- 스프레드 연산자...를 사용하여 대상 함수에 전달된 인수를 처리합니다.
Function.prototype.myCall = function (context, ...args) {
if (context === undefined || context === null) {
context = window
}
context.fn = this
const result = context.fn(...args)
delete context.fn
return result
}
let obj1 = {
num: 1,
sum(a, b) {
console.log(this)
return this.num + a + b
}
}
let obj2 = {
num: 10
}
console.log(obj1.sum.call(obj2, 2, 3)) // 15
console.log(obj1.sum.myCall(obj2, 2, 3)) // 15
apply() 및 수동 모의 구현
적용() 메서드
apply() 메서드를 호출하면 대상 함수가 즉시 실행되고 동시에 함수 내에서 this의 포인터가 변경됩니다. 이 점은 메서드의 첫 번째 매개변수에 의해 결정되며 두 번째 매개변수는 매개변수 배열 또는 인수 객체이며 각 배열 요소 또는 인수 객체가 나타내는 각 매개변수는 매개변수로 하나씩 전달됩니다. 목표 기능.
obj1.sum.apply(obj2, [2, 3])
수동 모의 구현
설계 논리:
- myApply() 메소드가 Function 프로토타입 객체에 추가됩니다. 대상 함수가 이 메소드를 호출하면 myApply() 메소드 내부의 this가 대상 함수를 가리킵니다.
- 컨텍스트 개체의 메서드로 대상 함수를 실행하여 대상 함수 내부의 this가 컨텍스트 개체를 가리킬 것입니다.
- 컨텍스트 개체에서 대상 함수를 제거합니다.
- 스프레드 연산자...를 사용하여 대상 함수에 전달된 인수를 처리합니다.
Function.prototype.myApply = function (context, args) {
if (context === undefined || context === null) {
context = window
}
// 下面这行为核心代码
context.fn = this
const result = context.fn(...args)
delete context.fn
return result
}
console.log(obj1.sum.apply(obj2, [2, 3])) // 15
console.log(obj1.sum.myApply(obj2, [2, 3])) // 15
bind() 및 수동 모의 구현
바인드() 메서드
bind() 메서드를 호출하면 함수 내에서 this의 포인터도 변경되지만 함수를 호출하는 대신 대상 함수의 복사본인 새 함수를 반환합니다. 함수 내에서 이것은 메서드의 첫 번째 매개 변수를 가리킵니다. 나중에 하나씩 나열될 임의 매개변수는 목적 함수의 매개변수로 하나씩 전달됩니다. 나중에 새 기능을 실행하는 것은 대상 기능을 실행하는 것과 같습니다.
bind() 메서드는 함수 커링을 구현하므로 대상 함수에 매개 변수를 두 번 전달할 수 있습니다. 첫 번째 매개 변수는 bind() 메서드의 첫 번째 매개 변수 뒤에 나열되고 두 번째 매개 변수는 새 함수에 나열됩니다.
obj1.sum.bind(obj2, 2)(3)
수동 모의 구현
설계 논리:
- myBind() 메서드는 Function 프로토타입 객체에 추가되며 대상 함수가 이 메서드를 호출하면 myBind() 메서드 내부의 this가 대상 함수를 가리킵니다.
- 컨텍스트 개체의 메서드로 대상 함수를 실행하여 대상 함수 내부의 this가 컨텍스트 개체를 가리킬 것입니다.
- 컨텍스트 개체에서 대상 함수를 제거합니다.
- 스프레드 연산자...를 사용하여 대상 함수에 전달된 초기 및 후속 인수를 처리합니다.
Function.prototype.myBind = function (context, ...initArgs) {
if (context === undefined || context === null) {
context = window
}
// 缓存 this 值
const _this = this
return function (...args) {
// 下面这行为核心代码
context.fn = _this
const result = context.fn(...initArgs, ...args)
delete context.fn
return result
}
}
console.log(obj1.sum.bind(obj2, 2)(3)) // 15
console.log(obj1.sum.myBind(obj2, 2)(3)) // 15