Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【JavaScript】call / apply / bind #11

Open
Tracked by #6
swiftwind0405 opened this issue Feb 25, 2020 · 1 comment
Open
Tracked by #6

【JavaScript】call / apply / bind #11

swiftwind0405 opened this issue Feb 25, 2020 · 1 comment

Comments

@swiftwind0405
Copy link
Owner

swiftwind0405 commented Feb 25, 2020

关于这块真的是基础的基础,曾经在遇到的时候一次又一次的跳过,包括用一些其他方式给解决了,但是若想深入,甚至看各种源码的时候,也是绕不开的知识点,必须好好学习。

区别

callapplybind 都可以改变函数的执行上下文,也就是函数运行时 this 的指向。

区别在于,callapply 改变了函数的执行上下文后会执行该函数,而 bind 不会执行该函数而是返回一个新函数。在参数的处理上,callapply 的第一个参数都是函数运行时的 this 值,区别在于,call 方法接受的是参数列表,apply 接受的是一个参数数组或类数组对象。

apply

apply 接受一个函数运行时的 this 值和一个参数数组或类数组对象,与 call 的区别在于对参数处理不同。

手写实现:

Function.prototype.apply = function(context, args) {
  // 对this的判断
  if (typeof this !== "function") {
    throw new TypeError("Error")
  }
  // 可对context的判断再做优化
  context = context || window
  // 可对第二参数进行容错,数组或者类数组
  args = args || []
  // 给context新增一个独一无二的属性以免覆盖原有属性
  const key = Symbol()
  context[key] = this
  const result = context[key](...args)
  // 带走产生的副作用
  delete context[key]
  return result
}

call

call 接受一个函数运行时的 this 值和一个参数列表,如果不指定第一个参数时,默认执行上下文为 window,改变 this 指向后,需要让新对象可以执行该函数,并能接受参数。

手写实现:

//传递参数从一个数组变成逐个传参了,不用...扩展运算符的也可以用arguments代替
Function.prototype.call = function (context, ...args) {
    //这里默认不传就是给window,也可以用es6给参数设置默认参数
    context = context || window;
    args = args ? args : [];
    //给context新增一个独一无二的属性以免覆盖原有属性
    const key = Symbol();
    context[key] = this;
    //通过隐式绑定的方式调用函数
    const result = context[key](...args);
    //删除添加的属性
    delete context[key];
    //返回函数调用的返回值
    return result;
}

bind

bind 接受一个函数运行时的 this 值和一个参数列表,返回一个新函数。

手写实现:

  • 实现一:
Function.prototype.bind = function (context, ...args) {
    const fn = this
    args = args ? args : []
    return function newFn(...newFnArgs) {
        if (this instanceof newFn) {
            return new fn(...args, ...newFnArgs)
        }
        return fn.apply(context, [...args,...newFnArgs])
    }
}
  • 实现二:
Function.prototype.bind = function (objThis, ...params) {
    const thisFn = this; // 存储源函数以及上方的params(函数参数)
    // 对返回的函数 secondParams 二次传参
    let fToBind = function (...secondParams) {
        const isNew = this instanceof fToBind // this是否是fToBind的实例 也就是返回的fToBind是否通过new调用
        const context = isNew ? this : Object(objThis) // new调用就绑定到this上,否则就绑定到传入的objThis上
        return thisFn.call(context, ...params, ...secondParams); // 用call调用源函数绑定this的指向并传递参数,返回执行结果
    };
    if (thisFn.prototype) {
        // 复制源函数的prototype给fToBind 一些情况下函数没有prototype,比如箭头函数
        fToBind.prototype = Object.create(thisFn.prototype);
    }
    return fToBind; // 返回拷贝的函数
};

参考资料

@swiftwind0405 swiftwind0405 changed the title call, apply 及 bind 函数 【Day14】call/apply/bind 函数 Mar 15, 2020
@swiftwind0405 swiftwind0405 changed the title 【Day14】call/apply/bind 函数 【Day14】call / apply / bind 函数 Mar 15, 2020
@swiftwind0405 swiftwind0405 changed the title 【Day14】call / apply / bind 函数 【Day14】call / apply / bind Mar 30, 2020
@swiftwind0405 swiftwind0405 changed the title 【Day14】call / apply / bind 【JavaScript】call / apply / bind Apr 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant