重温Javascript八股文 -—call,bind,apply以及 this的指向

call &apply

call 可以将某个对象原本没有的方法,进行劫持,通过改变this指向让该对象也具备这种能力。

应用场景
判断js数据类型
Object.prototype.toString.call('需要判断的数据')
对象冒充式继承
function a() {
  this.name = "a";
}
// a是超类;
a.prototype.play = function () {
  //   console.log(this.name, this);
};
function b() {
  this.name = "b";
  a.prototype.play.call(this); //冒充
}
b();
console.log(name);

call和apply的功能是一样的,当函数有形参传入时,apply写法上更加简洁。

第一个参数是需要改变this指向的ob。j

call 执行函数,并且将该函数中this指向call的第一个参数,如果该函数有参数,那么call的第二个参数开始一一带入所有参数。

apply 执行函数,并且将该函数中this指向call的第一个参数,如果该函数有参数,那么apply的第二个参数是这个函数的所有参数组成数组。

eg:
      var obj = {
        abc: function (_a, _b) {
          this.a = _a;
          this.b = _b;
        },
      };
      obj.abc(1, 2);
      console.log(obj);
call
实现call
Function.prototype.call = function(context = window,...args){
	//将调用call的函数挂在传入的对象上,起到更改this的目的
	context.fun = this;
	//执行方法,并传入参数
	const result = context.fun(...args);
	//执行完毕删除刚创建的自定义方法,防止污染
	delete context.fun;
	//返回结果
	return result
}

使用
      var obj = {
        abc: function (_a, _b) {
          this.a = _a;
          this.b = _b;
        },
      };
      var obj2 = {};
      obj.abc.call(obj2, 1, 2);
      console.log("obj:", obj, "obj2:", obj2);
apply
 var obj = {
        abc: function (_a, _b) {
          this.a = _a;
          this.b = _b;
        },
      };
      var obj2 = {};
      obj.abc.apply(obj2, [1, 2]);
      console.log("obj:", obj, "obj2:", obj2);

二者写法上有些许区别,实际作用一致。

call&apply指向

如果使用call或者apply,第一个参数是null,就意味着将函数中this重定向到window

什么时候用apply
当参数是类数组对象时
var arr=[1,3,5,6]
var max=Math.max.apply(null,arr);

因为Math.max没有this,null,传入以后并没有任何作用,目的是传参时传入的是数组

callapply的不同在于,callapply调用后会立即执行,返回值依赖于调用他们的函数。而bind,调用后会返回原函数,拥有指定的this以及初始参数。

bind

当需要在回调函数中重新执行回调函数中的·this,就需要用bind来指向对象。bind只是创建一个新函数,不会执行。

在某些场景下,使用ES6箭头函数可以替代实现bind需求。

      function fn1(fn) {
        fn(3);
      }
      function fn2(_a) {
        this.a = _a;
      }
      // 当需要在回调函数中重新执行回调函数中的this,就需要是用bind来指向对象
      var obj = {};
      // 把fn2函数中的this指向obj,并且返回这个被指向this后新的函数
      fn1(fn2.bind(obj));
      console.log(obj);
      var fns = fn2.bind(obj);
      // 这里创建了一个新的函数
      console.log(fns === fn2);//false

实现Promise

        class Promise1{
            status="pending";
            constructor(fn){
                fn(this.resolve.bind(this),this.reject.bind(this));
            }
            resolve(result){
                if(this.status!=="pending") return;
                var ids=setTimeout((function(){
                    this.setVal("resolve",result);
                    clearTimeout(ids);
                }).bind(this),0);
            }
            reject(error){
                if(this.status!=="pending") return;
                var ids=setTimeout((function(){
                    this.setVal("reject",error);
                    clearTimeout(ids);
                }).bind(this),0);
            }
            then(_resolve,_reject){
                this._resolve=_resolve;
                this._reject=_reject;
            }
            catch(_reject){
                this._reject=_reject;
            }
            setVal(_status,arg){
                this.status=_status;
                if(_status==="resolve" && this._resolve){
                    this._resolve(arg);
                }else if(_status==="reject" && this._reject){
                    this._reject(arg);
                }
            }
        }

ts中的私有化public、privite等可以限定属性和方法在什么地方使用,还要啥闭包呀。

This指向

普通函数

中的this ---->window

     function fn(){
           console.log(this);//ES5 this--->window
          //  ES6 严格模式  this--->undefined
       }
       fn();

回调函数

中的this,除了事件回调函数以外

this----->window

      var arr = [1, 2, 3, 4];
      arr.forEach(function () {
        console.log(this); //window
      });

      var obj = {
        a: function (fn) {
          var arr = [1, 2, 3, 4];
          arr.forEach(function () {
            console.log(this); //window
          });

          setTimeout(function () {
            console.log(this); //window
          }, 1000);
          fn();
        },
        b: function () {
          console.log(this);
          // 直接指向b函数,this---》obj
          // 当把b当成回调函数带入a函数,并且执行,this--->window
        },
      };
      obj.b();
      obj.a(obj.b);
对象中的this

对象的属性如果使用this,这个this指向对象外部的this。

      var a = 20;
      var obj = {
        a: 1,
        b: this.a, //当创建到这一步时,当前这个对象没有创建完成
        // 因此this指向的是当前对象外的this,对象外是window
        c: function () {
          // 在这里只是创建了c是一个函数,没有执行c
          //   console.log(this);
          setTimeout(
            function () {
              console.log(o);
              console.log(this === o); //这个this和这个setTimeout外面的this相同
            }.bind(this),
            2000
          );
          //当使用bind后,这个回调函数参数中的this和函数外this是相同的,也就是obj
        },
        d: () => {
          console.log(this); //因为使用箭头函数,所以this被指向当前函数外的this指向
        },
      };
      var o = obj;
      obj.c(); //当执行obj.c时,obj对象是已经创建完成的,因此c函数中this就是函数外的对象自身
事件函数

​ 事件函数,任何事件函数,this都会执行这个事件侦听的对象


      document.addEventListener("click",clickHandler);
      function clickHandler(e){
          console.log(this);//document
      }

      var obj={
          a:function(){
              document.addEventListener("click",this.clickHandler);
          },
          clickHandler:function(){
              console.log(this);//document
          }
      }
箭头函数

箭头函数的this指向声明箭头函数所在作用域外的对象(形象比喻:指向箭头函数所在的祖父级对象)。
在“use strict”严格模式下,没有直接的挂载者(或称调用者)的函数中this是指向window,这是约定俗成的。在“use strict”严格模式下,没有直接的挂载者的话,this默认为undefined。

      var obj = {
        b: function () {
          const fun4 = () => {
            console.log(this);//{b: ƒ}
          };
          fun4();
          console.log("b", this);//{b: ƒ}
        },
      };
      obj.b(); 

箭头函数在对象内定义, 因此这里的this指向则为父方法执行所在的对象。

      var obj = {
        fun4: () => {
          console.log("fun4", this); //window
        },
        b: function () {
          obj.fun4();
          console.log("b", this); //{b: ƒ}
        },
      };
      obj.b();
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值