JavaScript函数中this的指向

总结:谁调用我,我就指向谁(es6箭头函数不算)

一、ES6之前

  • 每一个函数内部都有一个关键字是 this ,可以直接使用

  • 重点: 函数内部的 this 只和函数的调用方式有关系,和函数的定义方式没有关系

1、 函数内部的 this 指向谁,取决于函数的调用方式

1.1、全局定义的函数直接调用,this => window
 function fn() {
   console.log(this)
 }
 fn()
 // 此时 this 指向 window
1.2、 对象内部的方法调用,this => 调用者
var obj = {
  fn: function () {
    console.log(this)
  }
}
obj.fn()
// 此时 this 指向 obj
1.3、 定时器的处理函数,this => window
setTimeout(function () {
  console.log(this)
}, 0)
// 此时定时器处理函数里面的 this 指向 window
1.4、事件处理函数,this => 事件源
div.onclick = function () {
  console.log(this)
}
// 当你点击 div 的时候,this 指向 div
1.5、自调用函数,this => window
(function () {
  console.log(this)
})()
// 此时 this 指向 window
1.6 函数嵌套场景分析
  • 成员函数嵌套this继承一定会出问题
 <script>
     // "use strict";
     function A() {
         console.log("A",this)
         function B(){
             console.log("B", this);
         }
         B();
     }

     A();

     var o = {             // 对象o
         m: function() {      //对象的方法m
             console.log(this);
             f();                   //调用嵌套函数
             function f() {         //嵌套函数f
                 console.log(this);
             }
         }
     }
     o.m();
 </script>

非严格模式,打印结果如下
JavaScript函数中this的指向_第1张图片
对于类中成员函数嵌套的情况,考虑使用箭头函数,这样this就不会乱,一直都是对象。

2、改变this指向

call 和 apply 和 bind

  • 刚才我们说过的都是函数的基本调用方式里面的 this 指向
  • 我们还有三个可以忽略函数本身的 this 指向转而指向别的地方
  • 这三个方法就是 call / apply / bind
  • 是强行改变 this 指向的方法
call
  • call 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向

  • 语法: 函数名.call(要改变的 this 指向,要给函数传递的参数1,要给函数传递的参数2, ...)

    var obj = { name: 'Jack' }
    function fn(a, b) {
      console.log(this)
      console.log(a)
      console.log(b)
    }
    fn(1, 2)
    fn.call(obj, 1, 2)
    
    • fn() 的时候,函数内部的 this 指向 window
    • fn.call(obj, 1, 2) 的时候,函数内部的 this 就指向了 obj 这个对象
    • 使用 call 方法的时候
      • 会立即执行函数
      • 第一个参数是你要改变的函数内部的 this 指向
      • 第二个参数开始,依次是向函数传递参数
apply
  • apply 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向

  • 语法: 函数名.apply(要改变的 this 指向,[要给函数传递的参数1, 要给函数传递的参数2, ...])

    var obj = { name: 'Jack' }
    function fn(a, b) {
      console.log(this)
      console.log(a)
      console.log(b)
    }
    fn(1, 2)
    fn.apply(obj, [1, 2])
    
    • fn() 的时候,函数内部的 this 指向 window
    • fn.apply(obj, [1, 2]) 的时候,函数内部的 this 就指向了 obj 这个对象
    • 使用 apply 方法的时候
      • 会立即执行函数
      • 第一个参数是你要改变的函数内部的 this 指向
      • 第二个参数是一个 数组,数组里面的每一项依次是向函数传递的参数
bind
  • bind 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向

  • 和 call / apply 有一些不一样,就是不会立即执行函数,而是返回一个已经改变了 this 指向的函数

  • 语法: var newFn = 函数名.bind(要改变的 this 指向); newFn(传递参数)

    var obj = { name: 'Jack' }
    function fn(a, b) {
      console.log(this)
      console.log(a)
      console.log(b)
    }
    fn(1, 2)
    var newFn = fn.bind(obj)
    newFn(1, 2)
    
    • bind 调用的时候,不会执行 fn 这个函数,而是返回一个新的函数
    • 这个新的函数就是一个改变了 this 指向以后的 fn 函数
    • fn(1, 2) 的时候 this 指向 window
    • newFn(1, 2) 的时候执行的是一个和 fn 一摸一样的函数,只不过里面的 this 指向改成了 obj
方法 this 指向 参数传递方式 执行时机
call 指定 逐个传递 立即执行
apply 指定 数组形式传递 立即执行
bind 指定 逐个传递(可选) 返回新函数,需手动调用

二、ES6之后的箭头函数

箭头函数内部没有 this,箭头函数的 this 是上下文的 this

const input = document.getElementById('input');
const btn = document.getElementById('btn');
		
 const obj = {
	    value: 'Hello',
	    printWithRegularFunction: function() {
	      setTimeout(function() {
	        console.log('普通函数:', this.value); // 这里的 this 指向全局对象(window)
	      }, 1000);
	    },
	    printWithArrowFunction: function() {
	      setTimeout(() => {
	        console.log('箭头函数:', this.value); // 这里的 this 指向 obj 对象
	      }, 1000);
	    }
  };
	
btn.addEventListener('click', () => {
    obj.value = input.value; // 将输入框的值赋值给 obj.value
    obj.printWithRegularFunction();
    obj.printWithArrowFunction();
 });

运行结果 在这里插入图片描述

注意对象中的箭头函数

虽然箭头函数不能用于定义对象方法(因为它没有自己的 this),但可以在对象中定义箭头函数作为普通属性。

const obj = {
  name: 'Alice',
  sayHello: () => {
    console.log(`Hello, ${this.name}`); // 这里的 this 指向外层作用域
  }
};

obj.sayHello(); // Hello, undefined

注意:箭头函数不适合用于对象方法,因为它会丢失对对象 this 的绑定。尽管我们可能在方法中不使用this,且不访问其他成员属性。但是,一般当我们使用对象调用此方法时是希望它指向obj的,这违背了我们的本意。

你可能感兴趣的:(JavaScript,javascript,前端)