apply,call,bind 的异同
相同点
- 更改this指向
TIP
MDN:bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数
js
let obj = {
a: 1,
b: 2,
test() {
console.log(this.a + this.b)
}
}
obj.test() // 3
obj.test.apply({ a: 2, b: 2 }) // 4
obj.test.call({ a: 3, b: 3 }) // 6
obj.test.bind({ a: 4, b: 4 })() // 8
let obj = {
a: 1,
b: 2,
test() {
console.log(this.a + this.b)
}
}
obj.test() // 3
obj.test.apply({ a: 2, b: 2 }) // 4
obj.test.call({ a: 3, b: 3 }) // 6
obj.test.bind({ a: 4, b: 4 })() // 8
不同点
传参方式不一样
- bind(this,...argv)
- call(this,...argv)
- apply(this,[...argv])
js
function test(a, b) {
console.log(this, a + b)
}
test.call('call', 1, 2) // [String: 'call'] 3
test.apply('apply', [2, 4]) // [String: 'apply'] 6
test.bind('bind', 3, 6)() // [String: 'bind'] 9
function test(a, b) {
console.log(this, a + b)
}
test.call('call', 1, 2) // [String: 'call'] 3
test.apply('apply', [2, 4]) // [String: 'apply'] 6
test.bind('bind', 3, 6)() // [String: 'bind'] 9
简单实现
测试用例
js
function test(a, b) {
console.log(this, a + b)
}
function test(a, b) {
console.log(this, a + b)
}
mycall
js
Function.prototype.mycall = function (thisArg) {
if (typeof this !== 'function') {
throw "error"
}
if (!(thisArg instanceof Object)) {
thisArg = new Object(thisArg)
}
thisArg = thisArg || window
thisArg.fn = this
let args = [...arguments].slice(1)
let res = thisArg.fn(...args)
delete thisArg.fn
return res
}
test.mycall({ a: 1, b: 2 }, 1, 2) // { a: 1, b: 2, fn: [Function: test] } 3
// 不考虑边界情况的简单写法
Function.prototype.myCall = function (thisArg, ...argArray) {
thisArg = thisArg || window
thisArg.fn = this
let res = thisArg.fn(...argArray)
delete thisArg.fn
return res
}
Function.prototype.mycall = function (thisArg) {
if (typeof this !== 'function') {
throw "error"
}
if (!(thisArg instanceof Object)) {
thisArg = new Object(thisArg)
}
thisArg = thisArg || window
thisArg.fn = this
let args = [...arguments].slice(1)
let res = thisArg.fn(...args)
delete thisArg.fn
return res
}
test.mycall({ a: 1, b: 2 }, 1, 2) // { a: 1, b: 2, fn: [Function: test] } 3
// 不考虑边界情况的简单写法
Function.prototype.myCall = function (thisArg, ...argArray) {
thisArg = thisArg || window
thisArg.fn = this
let res = thisArg.fn(...argArray)
delete thisArg.fn
return res
}
myapply
js
Function.prototype.myapply = function (thisArg) {
thisArg = thisArg || window
if (!(thisArg instanceof Object)) {
thisArg = new Object(thisArg)
}
thisArg.fn = this
let res = null
if (arguments[1]) {
res = thisArg.fn(...arguments[1])
} else {
res = thisArg.fn()
}
delete thisArg.fn
return res
}
test.myapply({ a: 2, b: 4 }, [4, 4]) // { a: 2, b: 4, fn: [Function: test] } 8
// 简单写法
Function.prototype.myApply = function (thisArg, argArray = []) {
thisArg = thisArg || window
thisArg.fn = this
let res
if (argArray.length === 0) {
res = thisArg.fn()
} else {
res = thisArg.fn(...argArray)
}
delete thisArg.fn
return res
}
Function.prototype.myapply = function (thisArg) {
thisArg = thisArg || window
if (!(thisArg instanceof Object)) {
thisArg = new Object(thisArg)
}
thisArg.fn = this
let res = null
if (arguments[1]) {
res = thisArg.fn(...arguments[1])
} else {
res = thisArg.fn()
}
delete thisArg.fn
return res
}
test.myapply({ a: 2, b: 4 }, [4, 4]) // { a: 2, b: 4, fn: [Function: test] } 8
// 简单写法
Function.prototype.myApply = function (thisArg, argArray = []) {
thisArg = thisArg || window
thisArg.fn = this
let res
if (argArray.length === 0) {
res = thisArg.fn()
} else {
res = thisArg.fn(...argArray)
}
delete thisArg.fn
return res
}
mybind
js
Function.prototype.mybind = function (thisArg) {
const that = this
const args = [...arguments].slice(1)
return function F() {
const bindArgs = args.concat(...arguments)
if (this instanceof F) {
return new that(...bindArgs)
}
return that.apply(thisArg,bindArgs)
}
}
test.mybind('123', 4, 5)() // [String: '123'] 9
Function.prototype.mybind = function (thisArg) {
const that = this
const args = [...arguments].slice(1)
return function F() {
const bindArgs = args.concat(...arguments)
if (this instanceof F) {
return new that(...bindArgs)
}
return that.apply(thisArg,bindArgs)
}
}
test.mybind('123', 4, 5)() // [String: '123'] 9