JavaScript里的'this':怎么指向哪里,一文搞懂

277 阅读3分钟

在JavaScript编程中,this关键字是一个核心概念,它在不同上下文中有着不同的含义和指向,对理解对象方法、函数调用以及类的实例化至关重要。本文将深入探讨this的工作原理、其在不同场景下的指向规则,并介绍箭头函数如何改变了我们处理this的方式。

this的基础与重要性

this代表函数执行时的上下文环境,即函数“身处”何处执行。正确理解并运用this,能够使我们的代码更加灵活、高效,尤其是在面向对象编程和事件处理等场景中。它使得对象内部的方法能够访问和操作对象自身的属性,减少了外部传参的需要,显著提升代码的质量,提升了代码的可读性和可维护性。

this一般写在全局函数体体内。

this的指向规则

1. 默认绑定

在全局作用域中,非严格模式下,this指向全局对象,即浏览器中的window。当一个函数独立调用时,不带任何修饰符的调用,同样遵循这一规则。

var a=1
console.log(this.a)//浏览器中执行输出1
var a=2
function foo(){
    var a=1;
    console.log(this.a);
}
foo();//浏览器中执行输出2

2. 隐式绑定

当一个函数被某个对象所拥有,或者函数被某一个上下文对象调用时,该函数中的this指向该上下文对象。

var obj={
    a:1,
    foo:function(){
        console.log(this.a);
    }
}
obj.foo();//浏览器中执行输出1

3. 隐式丢失

当一个函数被多个对象链式调用时,this指向最近的那个对象

function foo(){
    console.log(this.a);
}

var obj={
    a:1,
    foo:foo
}
var obj2={
    a:2,
    obj:obj
}
obj2.obj.foo();//浏览器中执行输出1,this指向obj

4. 显示绑定

使用call(), apply()bind()方法可以显式地设置函数调用时的this值。这为我们在复杂场景下精确控制函数上下文提供了手段,尤其在需要跨上下文调用函数时非常有用。

var obj={
    a:1
}
function foo(x,y){
    console.log(this.a,x+y);
}

call()的使用

call()会把foo中的this指向到obj中,并将参数传入。

foo.call(obj,1,2)

apply()的使用

capply()会把foo中的this指向到obj中,并将参数以数组的形式传入。

foo.apply(obj,[2,3])

bind()的使用

bind()会把foo中的this指向到obj中,并返回一个函数体,且bind()bar()中都能进行传参,当bind()内的参数不足时,调用时的参数会用bar()内的参数。

const bar=foo.bind(obj,1)
bar(2)

5. new绑定

当使用new关键字创建实例时,构造函数内部的this会自动绑定到新创建的实例上。这是面向对象编程中定义和初始化对象的一种标准方式。

参考上文:深入原型:new当中的奥秘

箭头函数与this

箭头函数中没有this这个机制,写在箭头函数中的this那也是外层非箭头函数的。

以下面为例,fn()本来应该遵循默认绑定,输出undefined,但因为箭头函数没有this机制,所以thisfoo()的,通过obj.foo()的执行遵循隐式绑定,this指向obj,最终输出1。

// var obj = {
//     a: 1,
//     foo: function () {
//         const fn = () => {
//             console.log(this.a)
//         }
//         fn();
//     }
// }

// obj.foo()

手搓call()

实现原理:在myCall()中拿到foo(),让foo()引用到obj中,然后让obj触发,最后将foo()删除。

arguments[]:拿到方法传进来的所以参数。

var obj={
    a:1
}
function foo(x,y){
    console.log(this.a,x+y);
}
Function.prototype.myCall = function(){
    const context=arguments[0];//指obj
    const args=Array.from(arguments).slice(1);//拿到除对象之后的所有参数
    context.fn = this;//this指的是foo()
    const res=context.fn(...args);//触发foo()
    delete context.fn;//删除
    return res;//返回结果
}
console.log(foo.myCall(obj,2,3));

结语

this的动态性是JavaScript的一大特点,但也可能成为初学者的陷阱。理解this的各种绑定规则,掌握何时以及如何利用call()apply()bind()以及箭头函数来控制this的指向,对于编写高质量、易于维护的JavaScript代码至关重要。