js中this的指向问题

85 阅读4分钟

1.不在函数中的this指向?

浏览器环境就是指向全局对象window

node环境中是指向一个空对象

2.函数中的this

取决于如何调用这个函数:创建执行上下文的时候确定了这次函数调用的this指向。

调用方式示例函数中的this指向
通过new调用new method()新对象
直接调用method()全局对象
通过对象调用obj.method()前面的对象
call/apply/bindmethod.call(ctx)第一个参数

1. 通过new调用

function Person(name,age){
  this.name = name;
  this.age = age;
  this.say = function(){
    console.log(this); //指向的是通过这个构造函数创建的实例对象
  }
}

let p1 = new Person("小明",25);
p1.say();

2.直接调用

// 情况1
function test(){
  console.log(this); // this指向window
}
test();

// 情况2
var prop = 20;
let obj ={
  prop:1,
  print: function(){
     console.log(this); // this指向的是obj对象(通过对象调用)
     function test(){
       console.log(this); // this指向window(函数直接调用)
     };
     test()
  }
}
obj.print();

// 情况3:立即调用函数
(function(){
  console.log(this); //window
})()

3.通过对象调用

// 情况1
function print(){
 console.log(this.prop); // this指向的是obj对象,所以输出1
}
var prop = 20;
let obj ={
  prop:1,
}
obj.print = print;
obj.print();

// 情况2
var prop = 20;
let obj ={
  prop:1,
  print: function(){
     console.log(this.prop); // this指向的是obj对象,所以输出1
  }
}
obj.print();

// 情况3,多层嵌套对象的this指向
var prop = 20;
let obj ={
  prop:1,
  b: {
    prop:5,
    print: function(){
       console.log(this); // this指向的就是obj.b,输出5
    }
  }
}
obj.b.print();

所以通过对象调用普通函数(非箭头函数),method中的指向,谁调用,这个this就指向谁。

4.call/apply/bind调用

  1. call/apply:用来设置调用函数时函数体内的this对象的值。(改变函数的this指向)

apply("函数内this的指向","参数数组") call("函数内this的指向",参数1,参数2...)

//案例1
function fun() {
  console.log(this.name)
}

let cat = {
  name:"喵喵"
}
fun(); //this指向的是window,直接调用函数。window的name不设置就会返回"",若是其他不存的属性就返回undefined
fun.apply(cat); //此时通过apply改变了fun中的this指向,现在指向是cat,所以输出的是喵喵


// 案例2,传参
let cat = {
  name:"喵喵",
}
let dog = {
  name:"旺旺",
  eat(food1,food2){
     console.log("我喜欢吃"+food1+"和"+food2,this)
  }
}
dog.eat("肉","骨头"); // 输出“我喜欢吃肉和骨头”,this指向dog
dog.eat.apply(cat,["鱼","肉"]); // 输出“我喜欢吃鱼和肉”,this指向cat
dog.eat.call(cat,"鱼","肉"); // 输出“我喜欢吃鱼和肉”,this指向cat
// 这里也能看出来call和apply的区别就是传参的方式,call参数是一个个传,apply是通过数组的方式传。
  1. bind:创建一个新的函数实例,this值会绑定到传给bind()的对象

bind("函数内this的指向",参数1,参数2...)

let cat = {
  name:"喵喵",
}
let dog = {
  name:"旺旺",
  eat(food1,food2){
     console.log("我喜欢吃"+food1+"和"+food2,this)
  }
}
dog.eat.bind(cat,"鱼","肉"); // 这里不会输出,因为bind是返回的新的函数实例
let catEat = dog.eat.bind(cat,"鱼","肉");
catEat(); // 输出“我喜欢吃鱼和肉”,this指向cat

3.setTimeout和setInterval中this的指向

var prop = 20;
let obj ={
  prop:1,
  show(){
    console.log(this,this.prop); 
    // 对象调用,所以this是obj,prop是1
    setTimeout(function(){
      console.log(this,this.prop);
      // 这里setTimeout是window方法,所以指向是window
    },500)
  }
}
obj.show();

4.箭头函数的this指向

箭头函数的 this 指向的是定义箭头函数的上下文。

箭头函数的 this 是在创建它时外层 this 的指向。

箭头函数不绑定this,而是从定义它的作用域中继承this值,所 以call/apply/bind方法对它的this毫无影响。

  • 箭头函数定义的上下文是window,所以this的指向是window
var prop = 20;
const say = () =>{
  prop:22;
  console.log(this); // 指向window
  console.log(this.prop) //输出20
}
say();
  • 当箭头函数作为一个对象的方法的时候,并不会把this绑定到该对象上,而是继承了上一级作用域中的this值。
var prop=11;
var obj={
 prop:22,
 say:()=>{
   console.log(this.prop); //指向window,输出11
 }
}
obj.say();//输出的值为11.
  • setTimeout和setInterval中使用箭头函数的this指向不一定是window,而是继承上下文的this指向。
var prop = 20;
let obj ={
  prop:1,
  show(){
    console.log(this,this.prop); 
    // 对象调用,所以this是obj,prop是1
    setTimeout(()=>{
      console.log(this,this.prop);
      // 这里setTimeout是window方法,但是箭头函数会继承定义该函数上下文的this指向,这里的this指向是obj。
    },500)
  }
}
obj.show();