首页 > 其他分享 >说说bind、call、apply的区别?并手写实现一个bind的方法

说说bind、call、apply的区别?并手写实现一个bind的方法

时间:2024-11-21 12:30:32浏览次数:1  
标签:函数 bind 参数 thisArg call apply

bindcallapply 都是 JavaScript 中用于改变函数执行上下文(即函数内部的 this 指向)的方法,它们的主要区别在于:

  • call: 立即调用函数,并接受参数列表作为后续参数。
  • apply: 立即调用函数,并接受一个参数数组作为参数。
  • bind: 创建一个新的函数,该函数的 this 值被绑定到指定的值,并可以预先设置一些参数。它不会立即执行原函数,而是返回一个新的函数,可以在之后调用。

更详细的解释:

  • call(thisArg, arg1, arg2, ...): 第一个参数 thisArg 是要绑定到函数的 this 值。后续参数 arg1, arg2 等是传递给函数的参数。

  • apply(thisArg, [arg1, arg2, ...]): 第一个参数 thisArgcall 一样。第二个参数是一个数组(或类数组对象),包含传递给函数的参数。

  • bind(thisArg, arg1, arg2, ...): 第一个参数 thisArgcallapply。后续参数 arg1, arg2 等是预先设置给函数的参数。bind 返回一个新的函数,当这个新函数被调用时,预先设置的参数会先于新函数调用时传入的参数传递给原函数。

手写实现 bind 方法:

Function.prototype.myBind = function(thisArg, ...boundArgs) {
  const originalFunction = this; // 保存原函数

  // 返回一个新函数
  return function(...args) {
    // 合并预设参数和调用时传入的参数
    const allArgs = boundArgs.concat(args);

    // 使用 apply 调用原函数,并设置 this 值和参数
    return originalFunction.apply(thisArg, allArgs);
  };
};


// 测试用例:
function greet(greeting, name) {
  console.log(`${greeting}, ${name}! I am ${this.title}`);
}

const person = {
  title: "Professor"
};

const greetPerson = greet.myBind(person, "Hello");
greetPerson("John"); // 输出: Hello, John! I am Professor

const greetPerson2 = greet.myBind(person, "Hi", "Jane");
greetPerson2(); // 输出: Hi, Jane! I am Professor

const greetPerson3 = greet.myBind(person);
greetPerson3("Good morning", "David"); // 输出: Good morning, David! I am Professor


关键点解释:

  1. 保存原函数: const originalFunction = this; 保存对原函数的引用,以便在新函数内部调用。

  2. 返回新函数: bind 的核心是返回一个新函数,这个新函数会在之后被调用。

  3. 合并参数: boundArgs.concat(args) 将预设参数 boundArgs 和调用新函数时传入的参数 args 合并成一个数组 allArgs

  4. 使用 apply 调用原函数: originalFunction.apply(thisArg, allArgs) 使用 apply 方法调用原函数,并将 this 值设置为 thisArg,参数设置为合并后的参数数组 allArgs

这个手写实现涵盖了 bind 的核心功能。一些更完善的实现还会处理一些边缘情况,例如:

  • new 操作符: 当使用 new 操作符调用绑定函数时,绑定的 this 值会被忽略。
  • 返回函数的 prototype: 需要正确设置返回函数的 prototype 属性。

这个更完善的版本,可以参考MDN的polyfill:

if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // closest thing possible to throwing a TypeError in IE6-8
      // since it doesn't support accessing the 'caller' property
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          return fToBind.apply(this instanceof fNOP
                 ? this
                 : oThis || this,

标签:函数,bind,参数,thisArg,call,apply
From: https://www.cnblogs.com/ai888/p/18560442

相关文章

  • nginx 普通用户使用80端口启动nginx nginx: [emerg] bind() to 0.0.0.0:80 failed (13
    介绍当我们用普通用户执行启动nginx时,无法启动成功,报错nginx:[emerg]bind()to0.0.0.0:80failed(13:Permissiondenied)报错原因大家都知道默认情况下linux的1024以下端口是只有root用户才有权限占用,于是我们的tomcat,apache,nginx等等程序如果想要用普通用户来占用80端......
  • genaiscript踩坑:设置proxyman抓包、兼容qwen72b funtion-call
    genaiscript有个很棒的日志系统,但是碰到接口报错就没用了,还是得抓包来看,为了设置proxy,得修改源码。genaiscript是通过npx运行的,包的执行优先顺序是本地依赖目录npminstallgenaiscript——npm全局依赖目录npminstall-ggenaiscript——npx缓存目录从没有安装过本地包,在Mac上对......
  • 【IDER、PyCharm】智能AI编程工具完整教程:ChatGPT Free - Support Key call AI GPT-o1
    文章目录CodeMoss简介CodeMoss的模型集成如何安装和配置CodeMossIDER插件安装步骤CodeMoss的实战使用AI问答功能代码优化与解释优化这段代码解释这段代码文件上传与对话联网查询与GPT助手联网查询GPT助手提升开发效率的最佳实践结语更多文献CodeMoss......
  • java 创建线程的三种方法(Thread,Runnable,Callable)ExecutorService
    1.继承Thread类2.实现Runnable接口3.实现Callable接口4.线程池1.继承Thread类packagecom.chen;//创建线程的方式:继承Thread,重写run(),调用start()开启线程//注意,线程开启不一定立即执行,由cpu调度执行publicclassTestThread2extendsThread{@Overridepublicvoid......
  • bind、call、apply区别?如何实现?
    一、作用:call、apply、bind作用是改变函数执行的上下文,简而言之就是改变函数运行时的this指向二、区别call: 1.传入的参数不固定2.第一个参数是this绑定的对象,后面其余的参数是传入函数执行的参数列表3.第一个参数为null、undefined的......
  • 记一次切面中读取请求体报错 Cannot call getReader()
    问题写了一个切面来处理被指定自定义注解标注的方法:@Slf4j@Aspect@Component@RequiredArgsConstructorpublicclassMyAnnoAspect{privatefinalHttpServletRequestrequest;@Around("@annotation(myAnno)")publicObjecthandleMyAnno(ProceedingJoinPo......
  • useCallback 和 useMemo 使用场景
     一切为了性能,无论是useCallback还是useMemo还是memo,都是为了让不该渲染的组件不去渲染在学习useCallback、useMemo之前,我们需要知道一点,React的渲染是自顶而下,如果父组件渲染了,那么子组件也会渲染,其子孙组件“世世代代”都要渲染但如果父组件的渲染与子组件的pr......
  • Java:An attempt was made to call a method that does not exist. The attempt was ma
    1.问题描述一个字段的类型从int变成了bigint,实体类也要同步更新为Long。修改完后只更新了这个类,结果运行就报错了。根据日志来看说“EntityKsGc.getKscc()Ljava/lang/Long;”这个方法不存在,但就是修改这个类,改成了Long类型,确确实实存在,另外从eclipse来看,也只提示修改了......
  • 织梦自定义图片字段报错 Call to a member function GetInnerText()
    问题:添加自定义图片字段时,前台打开当前栏目列表出现 Fatalerror:CalltoamemberfunctionGetInnerText()onstring 错误。解决方法:修改 customfields.func.php 文件:打开 /include/customfields.func.php 文件,搜索:  $fvalue=trim($ntag->GetInnerTe......
  • tips1:WPF绑定的一种情况 Binding
    <CheckBoxMargin="10"VerticalAlignment="Center"IsChecked="{BindingRelativeSource={RelativeSourceTemplatedparent},Path=IsExpanded}"/>CheckBox的IsChecked属性使用了数据绑定机制,以实现与TemplatedParent......