JSthis指向问题大全(普通函数,箭头函数,匿名函数)

结论

  • 普通函数中this指向函数的对象
  • 箭头函数中的this指向该函数所在作用域指向的对象

关于作用域是什么,可以自行Google一下,后面会用例子说明

1.普通函数

代码:

function test(){
    
    
    var a = 1;
    console.log(this.a);
}
test(); //undefined

由于test函数是直接在外层函数运行的,所以test是被window对象调用的,所以这里的 this.a 对应的应该是全局变量而不是test函数里的局部变量,故输出undefined

this在此处的一个应用

在一般函数方法中使用 this 指代全局对象,从而添加全局变量

function a() {
    
    
    this.x = "test";
}
a();   //全局对象调用a,使得里面的this指向window
function b() {
    
    
    console.log(this.x);  //test
}
b();
console.log(x); //test

此处在函数a中用this添加了全局对象a,使得在函数b以及外层环境中都能访问到a

2.构造函数

构造函数中的this,指向其new出来的对象
new做了什么

  1. 创建了一个对象

  2. 把这个实例对象连接到了原型链上

  3. 改变了构造函数的this指向

  4. 把实例对象的地址赋值给左边变量

function Foo(){
    
    
    this.x = 10;
    console.log(this);    //Foo {x:10}
}
var foo = new Foo();
console.log(foo.x);      //10
console.log(foo);       //Foo {x:10}

可以看到Foo里面打印的this与对象foo一样

构造函数 prototype 属性

在 Foo.prototype.getX 函数中,this 指向的 foo 对象。不仅仅如此,即便是在整个原型链中,this 代表的也是当前对象的值。

function Foo(){
    
    
	//B
    console.log(this);  //Foo {}
    this.x = 10;
    console.log(this);  //Foo { x: 10 }
}
Foo.prototype.getX = function () {
    
    
	//E
    console.log(this);        //Foo {x: 10}
    console.log(this.x);      //10
}
var foo = new Foo();  //A
console.log(foo);   //C    Foo { x: 10 }  
foo.getX();      //D

执行顺序A-B-C-D-E,在执行A后,进入Foo代码块B,此时this已经指向了对象foo(与C出结果一样),不过此时this.x还没挂载上去,所以看不到this.x,后跳出B代码块后进入C,打印obj对象,后进入D,调用obj原型上的getX,最后可以看到进入E后,obj原型上的this也和obj相同,打印的this.x为10。

拓展

在其原型的getX方法中修改this.x

function Foo(){
    
    
    this.x = 10;
    console.log(this);    //Foo {x:10}
}
var foo = new Foo();
console.log(foo.x);      //10
console.log(foo);       //Foo {x:10}
function Foo(){
    
    
    console.log(this);  //Foo {}
    this.x = 10;
    console.log(this);  //Foo { x: 10 }
}
Foo.prototype.getX = function () {
    
    
    console.log(this);        //Foo {x: 10}
    this.x = 20;
    console.log(this);      // Foo { x: 20 }
    console.log(this.x);      //20   
}
var foo = new Foo();
console.log(foo);   //Foo { x: 10 }
foo.getX();
console.log(foo);   //Foo { x: 20 }
console.log(foo.x);   //在原型对象上修改之后,打印得20

在obj原型的方法上调用this,修改x,后打印的结果也是修改后的结果,表明在整个原型链中,this也是指向当前对象

对象中

如果函数作为对象的方法时,方法中的 this 指向该对象。

var obj = {
    
    
    x: 10,
    foo: function () {
    
    
        console.log(this);        //{x: 10, foo: ƒ}
        console.log(this.x);      //10
    }
};
obj.foo();

拓展1:方法内再定义函数

若在对象方法中再定义函数,则该函数指向全局window

//当vscode node运行js文件时,浏览器控制台运行打印this.x仍为undefind(var x改为x即正常),但是this指向正确
//具体原因我也不懂,不过可以看到确实this指向window
var x = 25;
//在VS code输出undefined
var obj = {
    
    
    x: 10,
    foo: function () {
    
    
        function f(){
    
    
            // console.log(this);      //Window
            console.log(this.x + "kkk");    //25
        }
        f();
    }
}
obj.foo();

若想要改正上述问题,把this,绑定给self即可

var x = 25;   
var obj = {
    
    
    x: 10,
    foo: function () {
    
    
        var self = this;
        function f(){
    
    
            console.log(self);      //{ x: 10, foo: [Function: foo] }
            console.log(self.x);    //10
        }
        f();
    }
}
obj.foo();

拓展2:匿名函数在对象中的使用

var nameH = 'China';  
var obj = {
    
    
    name : 'America',
    show : function() {
    
    
        return function(){
    
    
            console.log(this.nameH);
        }
    }
}

var a = obj.show();
a(); // China

返回匿名函数时,相当于

var a = function(){
    
    
    console.log(this.name);
}

调用对象为全局window

在DOM元素中

在一个 HTML DOM 事件处理程序里,this 始终指向这个处理程序所绑定的 HTML DOM 节点,就相当于是给函数传参,使 其运行时上下文改变了。
此处较少见,代码略,见情况六:DOM event this

箭头函数中

箭头函数体内的this对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。

var nameH = 'window'; 

var A = {
    
    
   name: 'A',
   sayHello: () => {
    
    
      console.log(this.nameH)
   }
}

A.sayHello();  //window

因为sayHello所在的作用域其实是最外层的js环境,因为没有其他函数包裹;然后最外层的js环境指向的对象是winodw对象,所以这里的this指向的是window对象。

var obj = {
    
    
    x: 10,
    foo: function() {
    
    
        var fn = () => {
    
    
            return () => {
    
    
                return () => {
    
    
                    console.log(this);      //Object {x: 10}
                    console.log(this.x);    //10
                }
            }
        }
        fn()()();   //A
    }
}
obj.foo();

因为最里层返回的箭头函数,不管嵌套多少层,他都是在A处运行,即在fn()里面,所以this指向obj,所以this.x等于10

call、apply或者 bind 改变this

var obj = {
    
    
    x: 10
}
function foo(){
    
    
    console.log(this);     //{x: 10}
    console.log(this.x);   //10
}
foo.call(obj);
foo.apply(obj);
foo.bind(obj)();

可以看到apply等可以改变普通函数的this指向,但是无法改变箭头函数中的指向,如下所示。

var A = {
    
    
    name: 'A',
    sayHello: function(){
    
    
       var s = () => console.log(this.name)
       return s//返回箭头函数s
    }
 }
var sayHello = A.sayHello();
sayHello();// 输出A 

var B = {
    
    
    name: 'B'
}
 
 sayHello.call(B); //还是A
 sayHello.call(); //还是A

猜你喜欢

转载自blog.csdn.net/qq_44742090/article/details/122868665