JS基础——call、bind、apply
三者均可用来改变函数绑定的this,使其成为我们指定的对象
- call()、apply()作用相似
- 区别是传递参数形式不同,call()传递的是参数列表,apply()传递的是数组
fn.call(thisArg,arg1,arg2,...)
fn.apply(thisArg,[arg1,arg2,...])
thisArg是当前作用域;arg1,arg2...是传递的参数
call() :接收参数是一个参数列表
例子
function sum(num1, num2) {
return num1 + num2
}
function callSum(num1, num2) {
return sum.call(this, num1, num2)
}
console.log(callSum(10,10))
call()能扩充函数赖以运行的函数作用域
例子
window.color = 'red'
var o = {color: 'blue'}
function getColor() {
console.log(this.color)
}
getColor() // red
getColor.call(this) // red
getColor.call(window) // red
getColor.call(o) // blue
尝试手写一下call()
// 手写call()方法
Function.prototype.myCall = function(thisArg, ...args) {
thisArg.fn = this // this指向调用call的对象,即我们要改变this指向的函数
return thisArg.fn(...args) // 执行函数并return其执行结果
}
// 尝试第一个例子
function sum(num1, num2) {
return num1 + num2;
}
function callSum(num1, num2) {
return sum.myCall(this, num1, num2);
}
console.log(callSum(10, 10)); // 20
// 尝试第二个例子
window.color = 'red';
var o = { color: 'blue' };
function sayColor() {
console.log(this.color)
}
sayColor(); // red
sayColor.myCall(this); // red
sayColor.myCall(window); // red
sayColor.myCall(o); // blue
call()能进行进一步优化
Function.prototype.myCall = function (thisArg,...args) {
var fn = Symbol('fn') // 声明一个唯一属性,防止fn覆盖已存在属性
thisArg = thisArg || window // 如果没有传入this,默认指向window对象
thisArg[fn] = this // 改变this指向的函数(指向调用call的对象)
var result = thisArg[fn](...args) // 执行函数
delete thisArg[fn] // 删除定义的fn属性
return result // 返回执行结果
}
apply() :接收参数是一个数组
对照手写call()写原生apply()
Function.prototype.myApply = function (thisArg, args) {
var fn = Symbol('fn')
thisArg = thisArg || window
var args1 = args ? args : [] // 判断是否传递了参数,未传参,就默认参数为空数组
thisArg[fn] = this
var result = thisArg[fn](...args1) // 虽然apply接收的参数形式是数组,但是在调用函数的时候还是要传递展开的数组
delete thisArg[fn]
return result
}
bind():创建一个函数实例,会被绑定到传递给bind()的值
window.color = 'red'
var o = {
color: 'blue'
}
function getColor() {
console.log(this.color);
}
var colorObject = getColor.bind(o)
colorObject() // blue
可通过apply()/call()实现bind
Function.prototype.myBind = function (rest) {
var self = this
var context = rest.shift() // 删除第一个参数,也就是执行环境
return self.apply(context, [...rest])
}