js中的call与apply

本文记录下call、apply、bind方法的作用及其区别。<!--more-->

this

js函数中的this指的是函数调用的上下文,可以理解为正常的函数调用方式是 fu.call(context),函数其他的调用方式都是这种方式的语法糖。context默认是undefined,在浏览器中规定全局函数当context为undefined或null,那么context就是window,也即this默认绑定。

绝大部分情况下,this与函数调用的方式有关,运行时绑定。

箭头函数的this是编译时绑定,指向调用位置最近的词法作用域,对象不构成词法作用域,词法作用域规定的是哪些代码才能够访问。

每个函数在被调用时都会自动获取两个特殊变量:this和arguments。内部函数在搜索这两个变量时只会搜索到其活动对象为止,不可能直接访问外部函数中的这两个变量。但可以通过将外部作用域中的this(arguments)对象保存在一个闭包能访问到的变量里替代匿名函数中的this(arguments)。

var obj = {
    param: 123,
    ff : () => console.log(this), // window, strict模式下是undefined
}
var obj = {
    param: 123,
    ff : function () {
      (() => console.log(this)))() // obj
      return () => console.log(this) // obj
    }, 
}

显式改变this

call、apply、bind都可以改变上下文即重定义this对象(函数中的this对象改变为传入的某个参数),但是call、apply是立即执行,而bind是返回一个改变上下文的函数副本,原来函数不发生变化。

apply方法接收两个参数,一个是函数运行的作用域,另一个是参数数组;call方法与apply方法不同之处在于传递给函数的参数必须列举出来。bind参数方式同call相同。

拓展

apply可以将一个数组默认转换成一个参数列表

  • 可以使用 Math.max得到数组中最大项:Math.max.apply(null,array)
  • Math.min得到数组中最小项。
  • Array.prototype.push合并两个数组:Array.prototype.push.apply(arr1,arr2)

模拟实现call和apply

可以从一下几点考虑来实现:

  • 不传入第一个参数,默认为 window
  • 改变了this指向,让新的对象可以执行该函数,那么思路就变成了给新的对象添加一个函数,然后再执行完以后删除。

call:

Function.prototype.myCall = function (context) {
    var context = context || window;
    // 给context添加一个属性
    context.fn = this; // 这里this就是指向调用的函数
    var args = [...arguments].slice(1); // call传递给函数的必须列举出来
    var result = context.fn(...args);
    delete context.fn;
    return result;
}

apply:

Function.prototype.myApply = function (context) {
    var context = context || window;
    context.fn = this;
    var result;
    if (arguments[1]) { // apply传递的是参数数组
        result = context.fn(...arguments[1]);
    } else {
        result = context.fn();
    }
    delete context.fn;
    return result;
}

bind:

Function.prototype.myBind = function (context) {
    if (typeof this != 'function) {
        throw new TypeError('Error');
    }
    var _this = this;
    var args = [...arguments].slice(1);
    // 返回一个函数
    return function F() {
        // 因为返回一个函数,可以使用 new F(),需要判断
        if (this instanceof F){
            return new _this(...args, ...arguments);
        }
        return _this.apply(context,args.concat(...arguments));
    }
}

this 指向问题

var length = 0;
function fn(){
    console.log(this.length);
}
var obj = {
    length: 6,
    method: function(){
        fn();
    }
}
var objBind = {
  length: 7,
  method: () => {
    fn()
  }
}
obj.method(); // 输出?
objBind.method();
// 箭头函数的 this 可以理解为动态绑定,与调用者无关
posted @ 2022-06-20 09:58  EGBDFACE  阅读(43)  评论(0编辑  收藏  举报