关于前端:前端百题斩015快速手撕callapplybind

公众号【执鸢者】提前解锁3斩
写该系列文章的初衷是“让每位前端工程师把握高频知识点,为工作助力”。这是前端百题斩的第15斩,心愿敌人们关注公众号“执鸢者”,用常识武装本人的头脑。

在百题斩【014】中曾经简要概述了call、apply、bind三个办法,这三者作用是雷同的,均能够扭转this指向,从而让某对象能够调用本身不具备的办法,本节将深刻了解这三者的实现原理。

15.1 call()

15.1.1 根底

call() 办法应用一个指定的 this 值和独自给出的一个或多个参数来调用一个函数。其返回值是应用调用者提供的this值和参数调用该函数的返回值,若该办法没有返回值,则返回undefined。

根本用法:

function.call(thisArg, arg1, arg2, ...)

小试牛刀

function method(val1, val2) {
    return this.a + this.b + val1 + val2;
}

const obj = {
    a: 1,
    b: 2
};

console.log(method.call(obj, 3, 4)); // 10

15.1.2 实现

实现一个call函数,将通过以下几个步骤:

  1. 获取第一个参数(留神第一个参数为null或undefined时,this指向window),构建对象
  2. 将对应函数传入该对象中
  3. 获取参数并执行相应函数
  4. 删除该对象中函数,打消副作用
  5. 返回后果
Function.prototype.myCall = function (context, ...args) {
    // 获取第一个参数(留神第一个参数为null或undefined时,this指向window),构建对象
    context = context ? Object(context) : window;
    // 将对应函数传入该对象中
    context.fn = this;
    // 获取参数并执行相应函数
    let result = context.fn(...args);
    // 打消副作用
    delete context.fn;
    // 返回后果
    return result;
}
// ……
console.log(method.myCall(obj, 3, 4)); // 10

15.2 apply()

15.2.1 根底

apply() 办法调用一个具备给定this值的函数,以及以一个数组(或类数组对象)的模式提供的参数。其返回值是指定this值和参数的函数的后果。call()apply()的区别是call()办法承受的是参数列表,而apply()办法承受的是一个参数数组

根本用法

func.apply(thisArg, [argsArray])

小试牛刀

function method(val1, val2) {
    return this.a + this.b + val1 + val2;
}

const obj = {
    a: 1,
    b: 2
};

console.log(method.apply(obj, [3, 4])); // 10

15.2.2 实现

apply和call的区别次要是参数的不同,所以其实现步骤的call大体相似,如下所示:

Function.prototype.myApply = function (context, arr) {
    context = context ? Object(context) : window;
    context.fn = this;

    let result = arr ? context.fn(...arr) : context.fun();

    delete context.fn;

    return result;
}
// ……
console.log(method.myApply(obj, [3, 4])); // 10

15.3 bind()

15.3.1 根底

bind() 办法创立一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时应用。该函数的返回值是一个原函数的拷贝,并领有指定的this值和初始参数。

根本用法

function.bind(thisArg[, arg1[, arg2[, ...]]])

小试牛刀

function method(val1, val2) {
    return this.a + this.b + val1 + val2;
}

const obj = {
    a: 1,
    b: 2
};

const bindMethod = method.bind(obj, 3, 4);
console.log(bindMethod()); // 10

15.3.2 实现

实现一个bind函数绝对较简单一些,应该留神以下几点:

  1. 可能扭转this指向;
  2. 返回的是一个函数;
  3. 可能承受多个参数;
  4. 反对柯里化模式传参 fun(arg1)(arg2);
  5. 获取到调用bind()返回值后,若应用new调用(当做构造函数),bind()传入的上下文context生效。
Function.prototype.myBind = function (context, ...args) {
    if (typeof(this) !== 'function') {
        throw new TypeError('The bound object needs to be a function');
    }

    const self = this;
    // 定义一个中装函数
    const fNOP = function() {};
    const fBound = function(...fBoundArgs) {
        // 利用apply扭转this指向
        // 承受多个参数+反对柯里化模式传参
        // 当返回值通过new调用时,this指向以后实例 (因为this是以后实例,实例的隐士原型上有fNOP的实例(fnop);fnop instanceof fNOP为true)
        return self.apply(this instanceof fNOP ? this : context, [...args, ...fBoundArgs]);
    }

    // 将调用函数的原型赋值到直达函数的原型上
    if (this.prototype) {
        fNOP.prototype = this.prototype;
    }
    // 通过原型的形式继承调用函数的原型
    fBound.prototype = new fNOP();

    return fBound;
}

1.如果感觉这篇文章还不错,来个分享、点赞吧,让更多的人也看到

2.关注公众号执鸢者,与号主一起斩杀前端百题

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理