JS中改变this指向的上下文调用的三种方法

418 阅读4分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路

一.描述及各自相同和不同

1.默认情况下,函数有三种调用方式

         普通函数: 函数名()          ->  this指向window
         
         对象方法:  对象名.方法名()   ->  this指向对象
         
         构造函数:  new 函数名()     ->  this指向new创建的实例对象
         

2.函数三种调用方式有一个共同点: this指向无法修改

3.函数上下文调用 : 用于修改函数中的this指向

         3.1 函数名.call(修改this,形参1,形参2...)
         
         3.2 函数名.apply(修改this, 数组/伪数组 )
         
         3.3 函数名.bind(修改this)

4. call和apply和bind区别

         4.1 传参方式不同 : call是逐一传参, apply是数组/伪数组 传参方式不同
         
         4.2 执行机制不同 : call和apply立即执行函数, bind不会立即执行函数
         
            * call和apply用一次,改一次
            
            * bind修改一次,终生有效
  

二. call

1.简单使用

 function fn(a,b){
           console.log( this )
           console.log(a+b)
       }

       //普通函数 调用函数
       fn(10,20)
       //上下文调用 : 函数名.call(修改this,形参1,形参2...)
       fn.call({name:'张三'},30,40)

输出结果

image.png

2. 使用场景

1. typeof 数据 : 检测数据类型

        * 有两种数据类型无法检测 : nullarray

2. 万能数据类型检测 : Object.prototype.toString.call( 数据 )

上代码

        //值类型(基本数据类型)
        let str = 'abc'
        let num = 123
        let bol = true
        let und = undefined
        let nul = null
        //引用类型(复杂数据类型)
        let arr = [10,20,30]
        let fn = function(){}
        let obj = {name:'张三'}

        

        console.log( Object.prototype.toString.call(str) )//'[object String]'
        console.log( Object.prototype.toString.call(num) )//'[object Number]'
        console.log( Object.prototype.toString.call(bol) )//'[object Boolean]'
        console.log( Object.prototype.toString.call(und) )//'[object Undefined]'
        console.log( Object.prototype.toString.call(nul) )//'[object Null]'
        console.log( Object.prototype.toString.call(arr) )//'[object Array]'
        console.log( Object.prototype.toString.call(fn) )//'[object Function]'
        console.log( Object.prototype.toString.call(obj) )//'[object Object]'

输出结果

image.png

三. apply

基本使用

      function fn(a,b,c){
       console.log( this )
       console.log(a+b)
   }

   //普通函数 调用函数
   fn(10,20,30)
   //(1) 函数名.call(修改this,形参1,形参2...)
   fn.call({name:'张三'},30,40,50)
   //(2) 函数名.apply(修改this,数组/伪数组)
   // apply自动遍历数组/伪数组, 然后按照元素顺序逐一传参
   fn.apply({name:'李四'},[30,40,50] )   
  

输出结果

image.png

使用场景1 伪数组转真数组

伪数组

    有数组三要素,但是没有数组的方法
    伪数组本质 : 对象类型

使用

       let weiArr = {
           0 : 20,
           1 : 30,
           2 : 40,
           length:3
       }

       console.log( weiArr )

       //伪数组转真数组 : 伪数组如果想要调用真数组的方法,就可以把伪数组转成真数组

       //ES5 : apply
       let arr1 = []
       //细节: 这里使用apply不是为了修改this,而是借助apply传参的特点(自动遍历伪数组传参)
       //apply后面传arr1作用:保持this不变。 因为arr1.push()默认this就是arr1,这里不需要修改this
       arr1.push.apply(arr1,weiArr)
       console.log(arr1)

       //ES6 : Array.from(伪数组)
       let arr = Array.from(weiArr)
       console.log(arr)

输出结果

image.png

使用场景2 求数组最大值

 let arr = [80,100,99,20,50]

       //1.js基础:擂台思想
       let max = arr[0]
       for(let i = 1;i < arr.length;i++){
           if( arr[i] > max ){
               max = arr[i]
           }
       }
       console.log(max)

       //2.js高级写法

       let max1 = Math.max.apply(Math,arr)
       console.log( max1 )

       //ES6
       //  ...是ES6新增的一种运算符,类似于apply也会自动遍历arr,然后逐一传参
       let max2 = Math.max(...arr)
       console.log(max2)

输出结果

image.png

bind

基本使用

    function fn(a, b, c) {
        console.log(this)
        console.log(a + b)
    }

    //普通函数 调用函数
    fn(10, 20, 30)
    //(1) 函数名.call(修改this,形参1,形参2...)
    fn.call({ name: '张三' }, 30, 40, 50)
    //(2) 函数名.apply(修改this,数组/伪数组)
    // apply自动遍历数组/伪数组, 然后按照元素顺序逐一传参
    fn.apply({ name: '李四' }, [30, 40, 50])
    //(3) 函数名.bind(修改this)
    // bind不会立即调用函数,而是得到一个修改this之后的新函数
    // bind一般用于修改不会立即执行的函数中的this : 定时器、事件处理函数
    let fn1 = fn.bind({ name: '王五' })
    fn1(6,7)

    //定时器中的this默认指向window
    setTimeout( function(){
        console.log(this)
    }.bind({name:'王五'}) , 3000)
  

输出结果

image.png

注意

    1. 上下文调用call apply bind修改 this指向
    2. this:环境对象
    3.注意点是 : 修改this必须是引用类型,如果是 stringnumberboolean,则js编译器会自动帮你转成
    对应的对象。 如果是undefinednull,则修改无效
    

    function fn() {
        console.log(this)
    }

    fn.call('abc')//new String('abc')
    fn.call(123)//new Number(123)
    fn.call(true)//new Boolean(true)
    fn.call(undefined)//window
    fn.call(null)//window
    fn.call()//window