一、用法
call,apply,bind这三个方法其实都是js函数原型上的方法,其功能都是用来改变函数内部this的指向。call,apply方法会立即执行,call的参数需一个一个传,而apply参数以数组方式传。bind这个方法特殊一点,参数需一个一个参,但是其并不会立即调用,而是返回一个函数,
并且该函数可作为构造函数使用。当该返回的函数作为构造函数使用时,其内部this指向这个构造函数new出来的实例对象。
- call方法的使用
window.name = '李四'
function test(a, b) {
console.log(this.name, a, b)
}
const obj = {
name: '张三'
}
test.call(obj, '1', '2') // 张三 1 2 此时this指向obj
test('1', '2') // 李四 1 2 浏览器环境下this指向window
- apply方法的使用
function test(...arg) {
console.log(this.name, ...arg) // 张三 1 2
}
const obj = {
name: '张三'
}
test.apply(obj, ['1', '2']) // 参数以数组方式传递
- bind方法的使用
// 1、返回的函数作为普通函数使用
function test(a, b, c) {
console.log(this.name, a, b, c) // 张三 1 2 (此时this指向你传进来的obj)
}
const obj = {
name: '张三'
}
test.bind(obj, '1', '2')('3')
// 2、返回的函数作为普通函数使用
function test1(a, b, c, name) {
this.name = name
console.log(this.name, a, b, c) // 王五 1 2 (此时this指向返回的构造函数的实例)
}
const obj1 = {
name: '张三'
}
const S = test1.bind(obj1, '1', '2', '3')
const s = new S('王五')
二、实现
1、实现call方法
window.name = '李四'
Function.prototype.myCall = function (obj, ...arg) {
obj = obj || window
key = Symbol('key') // 避免与obj的属性相同,将其覆盖
obj[key] = this // 拿到调用的函数,并赋值给obj
obj[key](...arg)
delete obj[key] // 运行完删除属性,避免obj无故新增属性
}
function test(a, b) {
console.log(this.name, a, b)
}
const obj = {
name: '张三'
}
test.myCall(obj, '1', '2') // 张三 1 2
test('1', '2') // 李四 1 2
- 实现apply方法
Function.prototype.myApply = function (obj, arg) {
obj = obj || window
key = Symbol('key') // 避免与obj的属性相同,将其覆盖
obj[key] = this // 拿到调用的函数,并赋值给obj
obj[key](...arg)
delete obj[key] // 运行完删除属性,避免obj无故新增属性
}
function test(a, b) {
console.log(this.name, a, b)
}
const obj = {
name: '张三'
}
test.myApply(obj, ['1', '2']) // 张三 1 2
3、实现bind方法
Function.prototype.myBind = function (obj, ...arg) {
obj = obj || window
let key = Symbol('key')
obj[key] = this
const _this = this
return function (...Arg) {
let arr = [...arg, ...Arg]
if(this instanceof _this) { // 重点:这里是判断该函数是否是当构造函数使用
let newKey = Symbol('newKey')
this[newKey] = _this
this[newKey](...arr)
delete this[newKey]
}else {
obj[key](...arr)
delete obj[key]
}
}
}
// 1、返回的函数作为普通函数使用
function test(a, b, c) {
console.log(this.name, a, b, c) // 张三 1 2
}
const obj = {
name: '张三'
}
test.myBind(obj, '1', '2')('3')
// 2、返回的函数作为普通函数使用
function test1(a, b, c, name) {
this.name = name
console.log(this.name, a, b, c) // 张三 1 2
}
const obj1 = {
name: '张三'
}
const S = test1.myBind(obj1, '1', '2', '3')
const s = new S('王五')
总结:
call,bind,apply都是用来改变函数内部this指向的,只是在使用方式上有点不同而已。比较特殊的是bind,他不会立即执行,返回的函数既可以当普通函数,又可以当构造函数使用。