前端百题斩【015】——快速手撕call、apply、bind

简介: 前端百题斩【015】——快速手撕call、apply、bind

在百题斩【014】中已经简要概述了call、apply、bind三个方法,这三者作用是相同的,均可以改变this指向,从而让某对象可以调用自身不具备的方法,本节将深入理解这三者的实现原理。


15.1 call()


640.jpg

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()


640.jpg

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()


640.jpg

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;
}


相关文章
|
4月前
|
前端开发 JavaScript 开发者
揭秘JavaScript魔法三剑客:call、apply、bind,解锁函数新世界,你的前端之路因它们而精彩!
【8月更文挑战第23天】在 JavaScript 的世界里,`call`、`apply` 和 `bind` 这三个方法常常让新手感到困惑。它们都能改变函数执行时的上下文(即 `this` 的指向),但各有特点:`call` 接受一系列参数并直接调用函数;`apply` 则接收一个参数数组,在处理不确定数量的参数时特别有用;而 `bind` 不会立即执行函数,而是创建一个新版本的函数,其 `this` 上下文已被永久绑定。理解这三个方法能帮助开发者更好地运用函数式编程技巧,提升代码灵活性和可维护性。
45 0
|
7月前
|
前端开发 JavaScript
【Web 前端】 js中call、apply、bind有什么区别?
【4月更文挑战第22天】【Web 前端】 js中call、apply、bind有什么区别?
【Web 前端】 js中call、apply、bind有什么区别?
|
7月前
|
前端开发 JavaScript
前端 JS 经典:apply、call、bind
前端 JS 经典:apply、call、bind
98 0
|
前端开发
前端扫盲202307手写apply
前端扫盲202307手写apply
64 0
|
2月前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
194 2
|
2月前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
56 0
|
2月前
|
人工智能 自然语言处理 运维
前端大模型应用笔记(一):两个指令反过来说大模型就理解不了啦?或许该让第三者插足啦 -通过引入中间LLM预处理用户输入以提高多任务处理能力
本文探讨了在多任务处理场景下,自然语言指令解析的困境及解决方案。通过增加一个LLM解析层,将复杂的指令拆解为多个明确的步骤,明确操作类型与对象识别,处理任务依赖关系,并将自然语言转化为具体的工具命令,从而提高指令解析的准确性和执行效率。
|
2月前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
2月前
|
机器学习/深度学习 弹性计算 自然语言处理
前端大模型应用笔记(二):最新llama3.2小参数版本1B的古董机测试 - 支持128K上下文,表现优异,和移动端更配
llama3.1支持128K上下文,6万字+输入,适用于多种场景。模型能力超出预期,但处理中文时需加中英翻译。测试显示,其英文支持较好,中文则需改进。llama3.2 1B参数量小,适合移动端和资源受限环境,可在阿里云2vCPU和4G ECS上运行。
136 1
|
2月前
|
前端开发 算法 测试技术
前端大模型应用笔记(五):大模型基础能力大比拼-计数篇-通义千文 vs 文心一言 vs 智谱 vs 讯飞vsGPT
本文对比测试了通义千文、文心一言、智谱和讯飞等多个国产大模型在处理基础计数问题上的表现,特别是通过链式推理(COT)提示的效果。结果显示,GPTo1-mini、文心一言3.5和讯飞4.0Ultra在首轮测试中表现优秀,而其他模型在COT提示后也能显著提升正确率,唯有讯飞4.0-Lite表现不佳。测试强调了COT在提升模型逻辑推理能力中的重要性,并指出免费版本中智谱GLM较为可靠。
前端大模型应用笔记(五):大模型基础能力大比拼-计数篇-通义千文 vs 文心一言 vs 智谱 vs 讯飞vsGPT