call
,apply
,bind
,是 js
中非常重要的三个函数(Function)原型上的方法,我们来学习一下这三个方法。原型上的方法,我们需要通过实例来创建,意思就是我们需要先创建一个函数,通过关键字function
call( ctx, …args)
ctx
: 执行函数需要改变的this
对象 ;
args
: 执行函数需要传入的参数
我们来看一下call
的基本使用
function fn(name) {
console.log(this, name); // window 张三
}
fn('张三');
上面一段代码的this
指向为window
。
// 函数不变
function fn(name) {
console.log(this, name); // {name:'壳子i'} 我是谁
}
// 创建一个 obj
let obj = {name: '壳子i'}
// 通过call执行
fn.call(obj, '我是谁') //如果有多个参数在后面接着即可
apply(ctx, array)
ctx
:执行函数的this
指向;
array
:传入一个数组,我将数组的每一项作为函数的参数
function fn(name1, name2) {
console.log(this, name1, name2);
}
let obj = {name: '壳子i'};
let arr = ['张三', '李四'];
fn.apply(obj, arr) // =>{name: "壳子i"} "张三" "李四"
其实call
和apply
用法都是大同小异,就是传入的参数不同,他们都能传入多个参数,call
传入的是不定参数
,apply
传入的是一个具体的数组,数组里面包含所有参数。
我们来看看一个apply
的实际例子
求数组中最大值
通过循环的方式实现
let arr = [1, 2, 3, 4, 6, 8, 20, 3, 6, 8, 9, 3, 10],
max = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
console.log(max); // => 20
使用apply
let arr = [1, 2, 3, 4, 6, 8, 20, 3, 6, 8, 9, 3, 10],
max = Math.max.apply(null, arr);
cosnole.log(max)// => 20
可以看到代码量明显减少了很多
bind(ctx, arg…): bind 和call方法的参数是一样的,只是用法有些区别
bind执行后返回值是一个函数,
这个函数的this
被定死(绑定)为传入的ctx
对象且不可变
,
这个函数的参数也被定死(绑定)为...arg
且不可变
基本用法
function fn(num) {
console.log(this, num)
}
let obj = {name: '壳子i'}
let newFn = fn.bind(obj, 1)
newFn() // =>{name: "壳子i"} 1
我们说过参数和this都被绑死,我们来测试一下
function fn(num) {
console.log(this, num)
}
let obj = {name: '壳子i'}
let newFn = fn.bind(obj, 1)
newFn.bind(window, 2)() // => {name: "壳子i"} 1
newFn.call(window, 2) // => {name: "壳子i"} 1
newFn.apply(window, [2]) // => {name: "壳子i"} 1
newFn(2) // => {name: "壳子i"} 1
我们通过bind
绑定过后的方法,无论怎么执行都无法修改this
指向和参数的
注:以上三个方法如果不穿第一个参数,this
指向在非严格模式下均为window
我们来看一道面试题
function fn() {
console.log(this)
}
let obj = {name: '壳子'}
fn.call(obj) // ?
fn.call.call(function () {
console.log(this)
}) // ?
fn.call.call.call.call(function () {
console.log(this)
}, obj) // ?
我们一道一道分析
第一题没有什么好讲的 call
改变函数this
指向
结果是 {name:'壳子'}
我们重点来看后面两道题
第二题
首先我们要先知道一个知识点, this
的指向规则, 函数执行,如果是通过 xxx.fn执行的那么该函数(fn)的this
就指向xxx
如果大家不清楚可以在 js中的this指向 中查看(作者还在编写)
我们先来解析一下call
方法是怎么实现的,首先我们一般调用call
方法都是通过xxx.call(ctx, …args)的方法去调用。所以call
方法中this
就执行了fn
这个函数,那么我们就可以得出call
方法的执行逻辑
将this
函数中的this
修改为传入的ctx
(第一个参数), 然后再将自身的this
执行并把参数传入进去。
我们来实现一个call
方法
Function.prototype.myCall = function (ctx, ...args) {
let that = this.bind(ctx); // 改变this 的指向
return that(...args) // 执行this并返回结果
// 注:我们不能直接去修改 this 所以用that变量代替,但是在真实的call中就是this
}
function fn(num1) {
console.log(this, num1)
}
let obj = {name: '壳子'}
fn.myCall(obj, 2)
我们再来看看fn.call.call()
这段代码的含义是我们现在fn
中拿去call
方然后再通过**call**
方法去执行call
,所以实际上我们通过**call**
函数去执行的方法是前面的call
方法
所以这段代码会将 第一个参数(我们传入的匿名函数),然后将这个函数执行并且在非严格模式下,所以输出的this
是window
。
第三道题和第二题的理解方式都差不多,大家可以自己想想,如果有问题的话可以+作者qq:2573424017