call、apply、bind使用及一道经典面试题

callapplybind ,是 js中非常重要的三个函数(Function)原型上的方法,我们来学习一下这三个方法。原型上的方法,我们需要通过实例来创建,意思就是我们需要先创建一个函数,通过关键字functioncall、apply、bind使用及一道经典面试题_第1张图片

一、call

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

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"} "张三" "李四"

其实callapply用法都是大同小异,就是传入的参数不同,他们都能传入多个参数,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

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方法

所以这段代码会将 第一个参数(我们传入的匿名函数),然后将这个函数执行并且在非严格模式下,所以输出的thiswindow
call、apply、bind使用及一道经典面试题_第2张图片
第三道题和第二题的理解方式都差不多,大家可以自己想想,如果有问题的话可以+作者qq:2573424017

你可能感兴趣的:(js,javascript,es6)