apply、call和bind的区别?

https://segmentfault.com/a/1190000018017796
都是可以改变 this 的指向的。

  • apply 和 call 基本类似,他们的区别只是传入的参数不同。
    • apply第二个对象是数组
    • call多个参数平铺
  • bind 是创建一个新的函数,必须要手动去调用。
  1. func.apply(thisArg, [argsArray])
  2. func.call([thisArg[, arg1, arg2, ...argN]])
  3. let boundFunc = func.bind(thisArg[, arg1[, arg2[, ...argN]]])

执行结果/call

下面代码的输出是什么?

  1. const person = { name: "Lydia" };
  2. function sayHi(age) {
  3. console.log(`${this.name} is ${age}`);
  4. }
  5. sayHi.call(person, 21);
  6. sayHi.bind(person, 21);

A: undefined is 21 Lydia is 21 B: function function
C: Lydia is 21 Lydia is 21 D: Lydia is 21 function
答案:D 原因:.call方法会立即执行!.bind方法会返回函数的拷贝值,

手写apply和call

myCall

  1. Function.prototype.myCall = function (content) {
  2. const cxt = content || window;
  3. const args = Array.from(arguments).slice(1); // 类数组转换成数组
  4. const key = Symbol();
  5. cxt[key] = this; // 函数内部的this指向content
  6. let res = cxt[key](...args);
  7. delete cxt[key];
  8. return res;
  9. }

myApply

  1. Function.prototype.myApply = function (context, args) {
  2. context = context || window
  3. args = args ? args : []
  4. const key = Symbol() //给context新增一个独一无二的属性以免覆盖原有属性
  5. context[key] = this
  6. const result = context[key](...args) //通过隐式绑定的方式调用函数
  7. delete context[key] //删除添加的属性
  8. return result
  9. }

手写bind

https://github.com/mqyqingfeng/Blog/issues/12
⚠️ 返回function

  1. Function.prototype.myBind = function (context, ...args) {
  2. const fn = this
  3. args = args ? args : []
  4. return function newFn(...newFnArgs) {
  5. if (this instanceof newFn) {
  6. return new fn(...args, ...newFnArgs)
  7. }
  8. return fn.apply(context, [...args,...newFnArgs])
  9. }
  10. }

this的绑定方式优先级:箭头函数 -> new绑定 -> 显示绑定call/bind/apply -> 隐式绑定 -> 默认绑定

bind1:针对void 函数,简单的改变this指向

  1. Function.prototype.ebind = function(obj) {
  2. const func = this;
  3. return function () {
  4. return func.call(obj);
  5. }
  6. }
  7. // 测试
  8. let obj = {
  9. name: 'Jack',
  10. };
  11. let myFunc = function () {
  12. console.log(`${this.name}`);
  13. };
  14. let newFunc = myFunc.ebind(obj)
  15. newFunc() // Jack

bind2: 针对多个参数函数,改变this指向

  1. Function.prototype.ebind = function() {
  2. const func = this;
  3. const args = [...arguments];
  4. return function () {
  5. return func.call(...args);
  6. }
  7. }
  8. // 测试
  9. let obj = {
  10. name: 'Jack',
  11. };
  12. let myFunc = function (id) {
  13. console.log(`${this.name}, ${id}`);
  14. };
  15. let newFunc = myFunc.ebind(obj, 1287)
  16. newFunc() // Jack, 1287

bind3:

  1. Function.prototype.ebind = function() {
  2. const func = this;
  3. const args = [...arguments];
  4. return function () {
  5. const _args = [...arguments];
  6. return func.call(...args, ..._args);
  7. }
  8. }
  9. // 测试
  10. let obj = {
  11. name: 'Jack',
  12. };
  13. let myFunc = function (...args) {
  14. console.log(`${this.name}, ${args.join(', ')}`);
  15. };
  16. myFunc.ebind(obj, 1278)('Cheng Du', '天府一街')
  17. // Jack, 1278, Cheng Du, 天府一街

bind4: 支持

  1. Function.prototype.ebind = function() {
  2. const func = this;
  3. const args = [...arguments];
  4. return function Fn () {
  5. const _args = [...arguments];
  6. if (this instanceof Fn) {
  7. return new func(...args.slice(1), ..._args);
  8. }
  9. return func.call(...args, ..._args);
  10. }
  11. }
  12. // 测试
  13. let obj = {
  14. name: 'Jack',
  15. };
  16. let myFunc = function (...args) {
  17. console.log(`${this.name}, ${args.join(', ')}`);
  18. };
  19. let test1 = myFunc.ebind(obj, 1278);
  20. console.log(new test1('Cheng Du'));
  21. // Jack, 1278, Cheng Du