返回顶部
首页 > 资讯 > 前端开发 > JavaScript >一文搞懂JavaScript中bind,apply,call的实现
  • 941
分享到

一文搞懂JavaScript中bind,apply,call的实现

2024-04-02 19:04:59 941人浏览 泡泡鱼
摘要

目录bind、call和apply的用法bindcall&apply实现bind实现call和apply总结bind、call和apply都是Function原型链上面的方法

bind、call和apply都是Function原型链上面的方法,因此不管是使用function声明的函数,还是箭头函数都可以直接调用。这三个函数在使用时都可以改变this指向,本文就带你看看如何实现bind、call和apply。

bind、call和apply的用法

bind

bind()方法可以被函数对象调用,并返回一个新创建的函数。

语法:

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

bind()会将第一个参数作为新函数的this,如果未传入参数列表,或者第一个参数是nullundefined,那么新函数的this将会是该函数执行作用域的this。使用bind()应注意以下事项:

  • 返回一个新的函数,但是不会立即执行该函数
  • 根据传入的参数列表绑定this指向,如果未传入thisArg,那么需要明确this的指向
  • 如果是箭头函数,无法改变this,只能改变参数,这一点我们在这些情况下不建议你使用箭头函数也讲到过

举个例子:

正常使用

function fn(a) {
    console.log(this, a)
}
const fn1 = fn.bind({x: 100}); // fn1是一个函数,但是并没有立即执行
fn1(); // {x:100} 100
console.log(fn === fn1); // false,bind返回的是一个新的函数

箭头函数

const fn = (a) => {
    console.log(this, a);
}
const fn1 = fn.bind({x: 100}, 100); // 返回一个新的函数fn1,不会执行
fn1(); // window,100 箭头函数通过bind返回的函数无法修改其this指向

未绑定this,或绑定到null、undefined

const fn = (a) => {
    console.log(this, a);
}
const fn1 = fn.bind(); // 未绑定
const fn2 = fn.bind(null); // 绑定null
const fn3 = fn.bind(undefined); // 绑定undefined
fn1(); // 绑定到执行作用域,默认为window
fn2(); // 绑定到执行作用域,默认为window
fn3(); // 绑定到执行作用域,默认为window

call&apply

bind不同,callapply都是用来执行函数的,可以解决执行的函数的this指向问题。

语法:

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

call的参数列表是可选的,如果传入的thisArgnull或者undefined,那么会自动替换为全局对象;如果是传入的原始值,则会替换为原始值对应的包装类型。apply的用法和call类似,不同点在于其额外传入的参数是一个数组或类数组对象,而call的额外参数是不确定参数。

举个栗子:

function fn(a, b) {
    console.log(this, a, b);
}
fn.call({x: 100}, 10, 20); // {x: 100} 10 20
fn.apply({x: 100}, [10, 20]); // {x: 100} 10 20

callapply无法修改箭头函数的this指向:

const fn = (a, b) => {
    console.log(this, a, b);
}
fn.call({x: 100}, 10, 20); // Window 10 20
fn.apply({x: 100}, [10, 20]); // Window 10 20

简单回顾了以下bind、call、apply的使用,接下来就看看应该如何来实现。

实现bind

根据我们刚刚使用的bind(),在设计时需要如下考虑:

  • 最终返回的是一个新的函数,可通过function来声明
  • 需要绑定新函数的this
  • 需要绑定运行时的参数,可通过apply或call来实现

实现代码:

// 通过原型链注册方法
// context:传递的上下文this;bindArgs表示需要绑定的额外参数
Function.prototype.newBind = function (context, ...bindArgs) {
    const self = this; // 当前调用bind的函数对象

    // 返回的函数本身也是可以再传入参数的
    return function (...args) {
        // 拼接参数
        const newArgs = bindArgs.concat(args);
        return self.apply(context, newArgs)
    }
}
function fn(a,b) {
    console.log(this, a, b);
}
const fn1 = fn.newBind({x: 100}, 10);
fn1(20); // {x: 100} 10 20

bind()返回的是一个新函数,执行新函数就相当于是通过callapply来调用原函数,并传入this和参数。

实现call和apply

在实现bind的过程中,我们使用了apply来完成this的绑定,那么要实现apply又应该用什么来绑定this呢?可能会有小机灵鬼发现,好像在apply中使用call,在call中使用apply也可以完成this绑定。这不就形成了嵌套嘛,不是我们最终想要的。

我们先来

call和apply的应用:

  • bind返回一个新的函数,并不会执行;call和apply会立即执行函数
  • 绑定this
  • 传入执行参数

举个栗子:

function fn(a, b) {
    console.log(this, a, b);
}
fn.call({x: 100}, 10, 20); // {x: 100} 10 20
fn.apply({x: 100}, [10, 20]); // {x: 100} 10 20

call和apply的实现效果是一样的,都是立即执行函数,不同的是call需要传入单个或者多个参数,apply可以传入一个参数数组。

如何在函数执行时绑定this:

  • const obj = {x: 100, fn() {this.x}}
  • 执行obj.fn(),此时fn()内部的this指向的就是obj
  • 可以借此实现函数绑定this

使用过Vue的朋友都知道,Vue实例其实就是一个对象,其里面的方法在调用时,this就会指向当前对象。举个栗子:

let obj = {
    key: 'key',
    geTKEy: () => {
        return this.key;
    },
    getKey2() {
        return this.key;
    }
};
obj.getKey(); // this指向window,返回值取决于window中是否有对应的属性
obj.getKey2(); // this指向obj,返回 'key'

这个例子在这些情况下不建议你使用箭头函数也是有提及的,感兴趣的朋友可以去看看。根据此原理,我们就可以来尝试给函数绑定this了:某函数调用apply,那么我们就将这个函数添加到传入的this对象中(如果未传入则this为全局对象,如果传入的是原始值,则使用其包装类型),然后使用()来执行函数,这个时候函数的this指向的就是我们传入的this了。

实现代码:

Function.prototype.newCall = function(context, ...args) {
    if (context == null) context = globalThis; // 如果传入的上下文是null或者undefined,则使用全局globalThis,一般指向的就是window
    if (typeof context !== 'object') context = new Object(context); // 如果是原始类型(数字、字符串、布尔值等),则使用其包装类型

    const fnKey = Symbol(); // 使用Symbol可确保key值不会重复,避免属性覆盖
    context[fnKey] = this; // this指向的是当前调用newCall的函数

    console.log(context[fnKey]); // 打印当前函数以及上下文this
    console.log(context);

    const res = context[fnKey](...args); // 执行函数,函数的this指向为context
    delete context[fnKey]; // 删除fn,防止污染

    return res; // 返回结果
}
fn.newCall({x: 100}, 10, 20); // {x: 100} 10 20
function fn(a,b) {
    console.log(this, a, b);
}

这样我们就实现了call,那么apply实现类似,只不过传入的额外参数要变成数组或类数组的方式

Function.prototype.newCall = function(context, args) {
    if (context == null) context = globalThis; // 如果传入的上下文是null或者undefined,则使用全局globalThis,一般指向的就是window
    if (typeof context !== 'object') context = new Object(context); // 如果是原始类型(数字、字符串、布尔值等),则使用其包装类型

    const fnKey = Symbol(); // 使用Symbol可确保key值不会重复,避免属性覆盖
    context[fnKey] = this; // this指向的是当前调用newCall的函数

    console.log(context[fnKey]); // 打印当前函数以及上下文this
    console.log(context);

    const res = context[fnKey](...args); // 执行函数,函数的this指向为context
    delete context[fnKey]; // 删除fn,防止污染

    return res; // 返回结果
}
fn.newCall({x: 100}, 10, 20); // {x: 100} 10 20
function fn(a,b) {
    console.log(this, a, b);
}

注意打印的当前函数以及上下文:

实现callapplybind有很大的不同就是如何来处理this绑定。

总结

学会了如何实现bind、call和apply,对于理解如何使用,以及如何避免潜在的错误有很大的帮助。特别是callapply,我们在实现的时候借助于对象内部的非箭头函数,其this指向对象自身这一基础知识,实现了this绑定。如果还未搞清楚的朋友,可以将代码运行起来看看,也许能帮助你更好的理解。

以上就是一文搞懂javascript中bind,apply,call的实现的详细内容,更多关于JavaScript bind apply call的资料请关注编程网其它相关文章!

--结束END--

本文标题: 一文搞懂JavaScript中bind,apply,call的实现

本文链接: https://lsjlt.com/news/152460.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 一文搞懂JavaScript中bind,apply,call的实现
    目录bind、call和apply的用法bindcall&apply实现bind实现call和apply总结bind、call和apply都是Function原型链上面的方法...
    99+
    2024-04-02
  • 一文了解JavaScript中call/apply/bind的使用
    目录前言1. call1.1 语法1.2 流程图1.3 代码实现2. apply2.1 语法2.2 流程图2.3 代码实现3. bind3.1 语法3.2 流程图3.3 代码实现4....
    99+
    2024-04-02
  • JavaScript中call,apply,bind的区别与实现
    目录区别call实现apply实现bind实现bind 返回的函数 作为普通函数调用 代码实现bind 返回的函数 作为构造函数调用bind代码最终实现区别 call、apply、b...
    99+
    2024-04-02
  • JavaScript中call、apply、bind实现原理详解
    目录前言call用法实现简单的实现版本:升级版:apply用法实现bind用法基本版:升级版:总结前言 众所周知 call、apply、bind 的作用都是‘改变'作用域,但是网上对...
    99+
    2024-04-02
  • javascript怎么实现call、apply和bind方法
    本篇内容介绍了“javascript怎么实现call、apply和bind方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅...
    99+
    2024-04-02
  • Javascript实现call,bind,apply的代码怎么写
    这篇文章主要介绍了Javascript实现call,bind,apply的代码怎么写的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Javascript实现call,bind,apply的代码怎么写文章都会有所收...
    99+
    2023-06-29
  • Javascript动手实现call,bind,apply的代码详解
    1.检查当前调用的是否为函数 2.如果当前没有传入指向的this,则赋值为window 3.将fn指向当前调用的函数 4.获取传入的参数 5.将参数传入fn进行调用 6.将对象上的f...
    99+
    2024-04-02
  • JavaScript实现手写call/apply/bind的示例代码
    目录callcall的作用是啥总结applybind优化总结还记得之前面试得物的时候,上来就是一道手写bind,当时咱也不知道啥情况,也没准备什么手写的题目,就这样轻轻松松的挂了 现...
    99+
    2023-02-08
    JavaScript实现call apply bind JavaScript call apply bind JavaScript call JavaScript apply JavaScript b
  • 一文搞懂JavaScript中的内存泄露
    目录什么是内存泄漏怎么检测内存泄漏PerformanceMemory内存泄漏的场景垃圾回收算法引用计数循环引用标记清除闭包是内存泄漏吗总结以前我们说的内存泄漏,通常发生在后端,但是不...
    99+
    2024-04-02
  • 一文搞懂Java中对象池的实现
    目录1. 什么是对象池2. 为什么需要对象池3. 对象池的实现4. 开源的对象池工具5. JedisPool 对象池实现分析6. 对象池总结最近在分析一个应用中的某个接口的耗时情况时...
    99+
    2024-04-02
  • 一文搞懂JavaScript中的this指向问题
    一、全局环境下的this指向在全局作用域下,this始终指向全局对象window,无论是否是严格模式!congsole.log()完整的写法是window.console.log(),window可以省略,window调用了console....
    99+
    2023-05-14
    javascript
  • 一文搞懂JavaScript中的this绑定规则
    目录前言  this四大绑定规则一.默认绑定二.隐式绑定三.new绑定四.显示绑定绑定规则优先级面试题题1题2题3题4前言  首先我们来看一个示例。定义...
    99+
    2024-04-02
  • 一文搞懂JavaScript如何实现图片懒加载
    目录实现思路准备知识data-*getBoundingClientRect()throttlewindow.innerHeight完整代码js部分CSS部分运行结果总结图片懒加载,往...
    99+
    2024-04-02
  • 一文搞懂Spring中的JavaConfig
    目录配置类注册组件扫描包配置事务注解驱动单元测试加载配置类properties配置文件加载(了解)aspectj注解开关传统spring一般都是基于xml配置的,不过后来新增了许多J...
    99+
    2024-04-02
  • JS中call、apply和bind函数手写实现demo的方法是什么
    本篇内容介绍了“JS中call、apply和bind函数手写实现demo的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!JavaS...
    99+
    2023-07-05
  • 使用JS简单实现apply、call和bind方法的实例代码
    目录1.方法介绍2.apply、call和bind方法的实现2.1.apply的实现2.2.call的实现2.3.bind的实现总结1.方法介绍 apply、call和bind都是系...
    99+
    2024-04-02
  • 一文带你搞懂JavaScript中数组的特性
    目录前言基本介绍数组类型和判断判断为数组的方式数组索引值和长度索引值是字符串length属性数组的最大长度创建数组的三种方式数组字面量语法Array构造函数Array.of()空位(...
    99+
    2023-05-17
    JavaScript数组特性 JavaScript数组
  • 再谈JavaScript中bind、call、apply三个方法的区别与使用方式
    call的基本使用 var ary = [12, 23, 34]; ary.slice(); 以上两行简单的代码的执行过程为:ary这个实例通过原型链的查找机制找到Array.pro...
    99+
    2024-04-02
  • 一文搞懂JavaScript中原型与原型链
    目录前言构造函数创建对象prototype__proto__constructor实例与原型原型链总结constructor_proto_前言 js中的原型与原型链应该是老生常谈的话...
    99+
    2024-04-02
  • 一文搞懂C#实现读写文本文件中的数据
    【1】首先我们定义一段假数据,这里以一个string为例字   static void Main(string[] args) { string data = "我的数据要开始...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作