JS中this指向问题

一 普通的this指向 

1 在函数中this指向window全局对象,在严格模式下为undefined

2 在对象中调用this 指向对象本身

3 箭头函数的this 指向是在创建时就确定的 不会被改变,由于箭头函数的特性是捕获外层作用域的 this,这里的外层作用域是全局作用域,因此箭头函数中的this指向的是全局对象window

4 构造函数的this指向 当使用new关键字调用构造函数时,构造函数内部的this关键字指向新创建的对象实例。

      function ftn() {
        console.log(this);
      }
      ftn(); //Window
      console.log(this); //Window
      var obj = {
        name: "WeTab",
        printName: function () {
          console.log(this.name);
        },
        ftn: () => {
          console.log(this);
        },
      };
      obj.printName(); //WeTab
      obj.ftn(); //window
      function Person(name, age) {
        this.name = name;
        this.age = age;
        this.sayHello = function () {
          console.log(
            "Hello, my name is " +
              this.name +
              " and I am " +
              this.age +
              " years old."
          );
        };
      }
      const person1 = new Person("Alice", 30);
      person1.sayHello(); // 输出:Hello, my name is Alice and I am 30 years old.

二 简单练习题解析

1 函数内的this指向

        function ftn(val){
          this.count +=val
        }
        ftn.count=0
       console.log(ftn(1));//undefined

        因为ftn函数的this 指向的是全局对象window 而不是函数本身 所以this.count为undefined

2 对象中的this指向

         const obj={
        x:1,
        print:()=>{
          console.log(this.x);
        },
        print1(){
          console.log(this.x);
        },
        print2:function(){
          console.log(this.x);
        },
        print3:function(){
          console.log(this.x);
        }.bind(this)
      }
      obj.print() //undefined
      obj.print1()  // 1
      obj.print2()  // 1
      obj.print3() //undefined

print是一个箭头函数,箭头函数的特性是捕获外层作用域的this值。在这里,箭头函数 print中的 this 指向的是全局对象 window,因此 this.x 为 undefined。

print1是一个常规函数,常规函数中的 this 会根据调用方式的不同而变化。在这里,print1是作为对象obj的方法调用,因此 this 指向的是 obj对象,所以  this.x 的值为 1

print2也是一个常规函数,效果和print1 一样, this.x  的值为 1

print3是一个常规函数,并且使用了bind(this ) 方法来强制绑定 this 。然而,在对象字面量中无法通过 bind来改变 this 的指向,因此  this.x  为 undefined。

三 改变this指向的3种方法 call、apply、bind 的区别

1 call和apply改变this指向的同时会直接进行调用,而bind改变this指向的时候不会进行直接调用

       function greet() {
        console.log(`Hello, ${this.name}!`);
      }
      const person = { name: "Alice" };
      greet.call(person); // 输出 "Hello, Alice!"
      greet.apply(person); // 输出 "Hello, Alice!"
      greet.bind(person)//
      const ftn=greet.bind(person)
      ftn() //输出 "Hello, Alice!"

2 call和bind都是以单个参数的形式进行传参,而apply是以数组的形式进行传参

      function greet(greeting, punctuation) {
        console.log(`${greeting},${punctuation},${this.name}`);
      }
      const person = { name: "!" };
      greet.call(person,"Hello",'call')// 输出 "Hello,call,!"
      greet.apply(person,["Hello",'apply'])  输出 "Hello,apply,!"
      const boundGreet = greet.bind(person, "Hello",'bind');
      boundGreet(); // 输出 "Hello,bind,!"

3 综合练习题

      var name='hello'
      function Ftn(name){
        this.name=name,
        this.fool=function(){
          console.log(this.name);
        }
        this.foo2=()=>console.log(this.name);
        this.foo3=function(){
          return function (){
            console.log(this.name);
          }
        }
        this.foo4=function(){
          return ()=>{
            console.log(this.name);
          }
        }
      }
      var ftn1=new Ftn('ftn1')
      var ftn2=new Ftn('ftn2')
      ftn1.fool()  //ftn1
      ftn1.fool.call(ftn2) //ftn2
      console.log('foo2');
      ftn1.foo2() //ftn1
      ftn1.foo2.call(ftn2) //ftn1
      console.log('foo3');
      ftn1.foo3()() //hello
      ftn1.foo3.call(ftn2)() //hello
      ftn1.foo3().call(ftn2) //ftn2
      console.log('foo4');
      ftn1.foo4()() //ftn1
      ftn1.foo4.call(ftn2)() //ftn2
      ftn1.foo4().call(ftn2) //ftn1

解析:

        1 ftn1.fool(): 输出ftn1,因为fool方法直接在ftn1对象上调用的所以直接打印ftn1对象上的name

        2 ftn1.fool.call(ftn2): 输出 ftn2,因为通过使用call,将fool方法的中的this指向改变为ftn2对象,所以打印的是ftn2对象的 name 。

        3 ftn1.foo2(): 输出ftn1,因为foo2方法直接在ftn1对象上调用的所以直接打印ftn1对象上的name

        4 ftn1.foo2.call(ftn2):输出ftn1,因为箭头函数不能改变this指向,因此无论如何调用,都会以定义时的this指向为准,所以还是打印ftn1对象上的name

        5 ftn1.foo3()():输出hello 是因为return返回后的function 函数中的this 指向的是全局对象,所以最后输出的是全局对象下的name 。 这里注意 如果是let声明变量 是无法添加在全局对象上的, 如果是let name=hello  输出为“”

        6 ftn1.foo3.call(ftn2)():输出hello  这里call 改变的是第一个function指向而不是return后的this指向,所以return 后的function 还是指向全局对象

        7 ftn1.foo3().call(ftn2):输出ftn2,这里是使用call改变了return后的this指向 使其this指向ftn2 所以输出的是ftn2对象上的name

        8 ftn1.foo4()():输出ftn1 因为foo4 返回的是箭头函数,箭头函数的this指向声明时的对象,所以输出为fth1上的name

        9ftn1.foo4.call(ftn2)():输出ftn2 因为call 改变了function函数的指向 而不是要改变return回来的箭头函数 

        10 ftn1.foo4().call(ftn2):输出ftn1,因为return返回的时箭头函数 ,箭头函数的this指向无法被改变,所以依然打印ftn1上的name

        

你可能感兴趣的:(javascript,前端,vue.js)