在JavaScript中,this它指的是函数调用的上下文(context)即调用的函数的执行环境。

    在函数执行时,this 总是指向调用该函数的环境。要判断 this 的指向,其实就是判断 this 所在的函数是在哪个环境中。
    this 出现的场景分为四类,简单的说就是:

    • 有对象就指向调用对象
    • 没调用对象就指向全局对象
    • 用new构造就指向新对象
    • 通过 apply 或 call 或 bind 来改变 this 的所指。
    1. 如果是函数,就看这个函数在哪个对象中。
    1. function test() {
    2. let a = 4;
    3. console.log('第一层test:', this.a); // undefined
    4. console.log('第一层this:', this); // 全局对象
    5. // 闭包
    6. function c() {
    7. console.log('第二层c:', this.a) // undefined
    8. console.log('第二层this:', this) // 全局对象
    9. };
    10. c();
    11. };
    12. test();

    如上代码:因为不管 c 函数 或者 test 函数都是在全局对象中调用, 所以this 指向的都是 全局对象。即如果函数中,使用this, 那么这个this一定指的是包含这个函数的 对象。如下图:
    image.png

    test 函数 是存在 A对象中,所以,这个 this 指的就是 A 对象。

    总结就是:如果是函数使用this,那就往出跳一层,跳出这个函数。看这个函数是属于哪个对象的,即这个函数是在哪个对象里面申明的。

    函数调用的四种形式:

    • 普通的函数调用
    • 作为对象的方法调用
    • 作为构造函数调用
    • 通过它们的call()和apply()间接调用

    1)作为函数
    这是最通常的函数用法,属于全局性调用,因此this等于全局对象。

    1. function f(){
    2. window.x = 1;
    3. console.log(this.x);
    4. }
    5. f(); // 1

    对代码做些改变再看

    1. var x = 1;
    2. function f(){
    3. console.log(this.x);
    4. }
    5. f(); // 1
    6. console.log(window.x); // 1

    window.x与this.x值相等。再变一下

    1. var x = 1;
    2. function f(){
    3. this.x = -1;
    4. console.log(this.x);
    5. }
    6. f(); // -1
    7. console.log(x); // -1

    在f()中给this.x赋值为-1,结果x的值跟着改变为-1,所以this等于全局对象。

    2)作为方法
    当函数作为某个对象的方法调用时,这时this的值就是这个对象。

    1. function f(){
    2. console.log(this.x);
    3. }
    4. var o = {
    5. x: -1,
    6. m: f
    7. };
    8. o.m(); // -1
    9. o.x = 1;
    10. o.m(); // 1

    对象的属性值改变,f()里面this.x跟着改变。可以在f()里面打印一下this,看看结果呢!

    3)作为构造函数

    作为构造函数调用时,使用new关键字初始化一个实例对象,这时this等于这个实例对象。

    function f(){
        this.name = "zrn";
    }
    var o = new f();
    console.log(o.name); // "zrn"
    

    运行结果为”zrn”,表示这并非全局对象。变一下代码

    var name = "window";
    function f(){
        this.name = "zrn";
    }
    var o = new f();
    console.log(o.name); // "zrn"
    console.log(name); // "window"
    

    name的值互不干涉。

    4)通过call()或者apply()调用
    call()和apply()的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this的值。第一个参数(context)是函数运行的作用域,第二个参数是参数数组(argArr),不过使用call()时,要将这些参数逐个列举出来。如果未传递context,则context是全局对象(啊,说的有点多了)

    var name = "window";
    function f(){
        console.log(this.name);
    }
    var o = {name: "zrn"};
    f.call(); // "window", this指的是window
    f.apply(o); // "zrn", this指的是对象o