this以及call apply bind的用法和封装

450 阅读3分钟

call apply bind是用来改变this的指向的

先来说一下this吧

普通函数的this指向规律👇

1、 事件绑定的函数中的this,是指向当前操作元素的。

    var btn = document.getElementsById('btn')
    btn.onclick = function(){
    console.log(this)//=>this指的是当前操作的这个元素,也就是btn
}

2、 自执行函数中的this是指向 window的。

        btn.onclick = (function(){
        //赋予 onclick 的 该自执行函数的返回结果,也就是一个箭头函数
        return ()=>{
        console.log(this)//=>this是指向 window的
        }
           })();

3、 其他的函数执行中的this👉 看点 。

   function fn(){
    console.log(this);
     }
    var obj = {
         a:fn,
         b:12,
         c:13
     }
     var ary = [4,5,fn];
     var obj2 = {
         q:12,
         w:fn
     }
    
     fn(); //=> window          fn  obj.a   ary[2]   obj2.w  四者同一个地址
     obj.a(); //=> obj   👈看点
     ary[2](); //=> ary
     obj2.w(); //=> obj2   👈看点

箭头函数中没有this,箭头函数中把this当作变量向上级作用域查找

call apply bind的用法

一看就懂call的一道题

   function fn() {
        console.log([...arguments])
        console.log(this)
        return 123;
    }
    var obj = {
        a: 12,
        b: 13,
        qqq: 123,
        f: fn
    }
    fn(1,2,3)   //fn执行,this指向window,因为前面没点
    obj.f(6,6,6); //obj.f执行 , this指向obj,因为前面有点
    fn.call(obj,5,5,5); //将fn中的this原本的指向window改为obj,并且把5,5,5作为实参传进去

一看就懂apply的一道题

   //还拿这道题为例
    function fn() {
        console.log([...arguments])
        console.log(this)
        return 123;
    }
    var obj = {
        a: 12,
        b: 13,
        qqq: 123,
        f: fn
    }
    fn.apply(obj.[5,5,5]) //第二个参数是个数组或者类数组的集合;虽然是以一个集合的形势传过去的;但是 fn 接收时还是散乱的接收的

一看就懂bind的一道题

    //继续拿这道题为例
    function fn() {
        this.name = 123;
        this.age = 234;
        return 123;
    }
    var obj = {
         a:12,
         b:13
    }
    var f = fn.bind(obj,6,6,6,6);
    // f执行 让 fn执行; 并且把 6,6,6,6传给fn;fn中的this 指向是 obj;
    // 把 6,6,6,6 理解成 f 的默认参数;再给f传递参数的时候;会把传递的参数补在 默认参数的后边;
    console.log(f)
    

call apply 都是让函数立即执行了, bind是返回了一个新函数,使用bind改变过this的指向之后,this不再改变

封装一个Call

call 是用来改变函数内部得this指向的 在Function的原型上

call可以让函数执行 并且可以改变函数执行时 内部的this指向 this执行了call的第一个实参 call后面的所有参数都被传给前面的函数当作实参

实现一个myCall

 Function.prototype.myCall = function (context,...arg) {
        // context 就是我们让this指向的哪个值, arg是要传给对应函数的实参
        context = context  || window  //有传context的话this就指向context;没有传context得话this就指向window
        var n = Symbol(); //  Symbol是唯一值
        context[n] = this;  //确定this指向
        let res = context[n](...arg); 
        delete context[n]; 
        return res
    }

封装一个myApply

myApply的目的跟call一样 区别在于第二个参数 第二个参数是一个数组或者类数组

类数组转数组

  • [...xxx]
  • Array.from(xxx) :from在Array类上面,Array的实例是调不到from的,from和prototype是兄弟关系
  • [ ].slice.call(arguments,0)
  • arguments. _ _proto _ _ =Array.protitype

实现一个myBind

Function.prototype.myApply = function(context,ary){
    ary = ary || []
    context = context || window
    let n = Symbol()
    context[n]=this
    let arr = context[n](...ary)
    delete context[n]
    return arr
}

使用apply获取数组中的最大值

  var ary = [234,53,2342,45,234,464,2,6,45];
  
    Math.max.apply(Math,ary);// 利用了 apply 可以把集合散乱的传给前边的函数

//其他方法:

    Math.max(...ary);

    ary.sort((a,b)=>b-a)[0];

    // 假设法
    var max = ary[0]
    ary.forEach((v, i) => {
        if (v > max) {
            max = v
        }

    })

封装一个myBind

   var f = fn.bind(obj,1,2,3,4) 

bind的用法与call一样,只是bind返回一个新函数,新函数执行时 fn才会执行

fn中的this这时才被改成obj; f中的this 不会在发生任何改变了;再使用 call apply 也不好使;

call apply 都是让函数立即执行了;但是bind是返回了一个新函数;

实现一个myBind

Function.prototype.myBind = function(){
     var _this = this;
    return function(...ary){
      return _this.apply(context,arg.concat(ary))
    }
}