JavaScript 中 this 的用法

2,470 阅读3分钟
原文链接: mewhat.github.io

this关键字是JavaScript中最复杂的机制之一。它是一个很特别的关键字,被自动定义在所有函数作用域中。但是即便是经验丰富的JavaScript开发者也很难说清它到底指向什么:

任何足够先进的技术都和魔法无异。 ——Archur C.Clarke

误解

  • 指向自身 :在函数中的this误解为指向函数本身;(每个函数的this是在函数调用时被绑定的,完全取决去函数的调用位置(也就是函数的调用方法,而不是函数声明的位置))

    var count = 0;
    function foo(num) {
        console.log("foo: " + num);
        //尝试记录foo被调用的次数
        this.count++;
    }
    foo.count = 0;
    for(var i = 0; i < 5; i++) {
        foo(i);
    }
    console.log(foo.count);//0
    //如果没有在全局定义声明count并初始化,下面的会输出NaN
    console.log(count);//5
    /*
        上面的例子中函数foo中的this并不是指向函数本身,而是指向全局window对象,foo.count = 0为foo函数
        初始化了count变量,但是this.count的自增是对于全局的count而言的,如果全局没有初始化或者没有声明count
        的话,console.log(count)得到的结果就是NaN。
        以上说明this并不是指向函数本身
    */
  • 它的作用域:误解this指向函数的作用域。(this任何时候都不指向函数作用域,作用域“对象“无法通过
    JavaScript代码访问,因为它存在于JavaScript引擎内部。)

    function foo() {
        var a = 2;
        this.bar();
    }
    function bar() {
        console.log(this.a);
    }
    foo();
    /*
    foo函数中的this尝试调用全局的bar函数,这个是多余的一步,
    因为bar函数就在全局中,可以通过作用域链访问到
    然而bar函数中的this.a是指向全局window的,因为没有声明,所以返回undefined
    上面的代码企图访问作用域,失败了
    */

this的运用

  • 纯粹的函数调用:全局函数的调用,this代表的是全局对象window

    var foo = function() {
        console.log(this == window);
    }
    foo();//输出true
    //再次确认调用全局
    var a = 1;
    function test() {
        this.a = 0;
    }
    console.log(a);//1
    test();
    console.log(a);//调用test()改变全局a之后输出0
    
  • 作为对象的方法调用:作为某个对象的方法调用,this指向这个对象

    var obj = {
        method: function() {
            console.log(this === obj);//true
            console.log(this === window)//false
        }
    }
    obj.method();
  • 函数内调用内部函数:在函数内部调用函数,不管是在全局函数中调用函数,还是在方法中调用函数,this绑定全局window;也就是说子函数孙函数,只要是以函数的方式调用,this 就铁了心绑定 window 对象了

    var foo = function() {
        console.log(this === window)
        var method = function() {
            console.log(this == window)
        }
        method();
    }
    foo();
    //两个输出都是true
    //在某个对象的方法中调用函数
    var foo = {
        method: function() {
            console.log(this === foo);
            var methods = function() {
                console.log(window === this);
            }
            methods();
        }
    }
    foo.method();
    //两个都输出true
  • 作为构造函数调用:所谓的构造函数,就是通过这个函数生成一个新的对象

    function foo(name, age) {
        this.name = name;
        this.age = age;
    }
    var mewhat = new foo('mewhat','18');
    console.log(mewhat);
    //输出foo {name: "mewhat", age: "18"},同时还有一个__proto__原型对象
    //输出数据:{"name":"mewhat","age":"18"}
    console.log(JSON.stringify(mewhat));
    //为了表明this不是全局对象,对代码做了点改变
    var a = 2;
    function foo() {
        this.a = 1;
    }
    var test = new foo();
    console.log(a);//2,全局中的a并没有被改变
    console.log(test.a);//1
  • apply与call调用:apply()是函数对象的一个方法,它的作用是改变函数的调用对象,它的第一个参数就表示改变后的调用这个函数的对象,因此,this指的就是这第一个参数。call也是一样;apply与call的区别在于第二个参数,apply可以传递数组,而call只能是一个个数。

    var x = 0;
    function test() {
        console.log(this.x);
    }
    var o = {
        x: 1,
        m: function() {
            console.log(this.x);
        }
    };
    o.m.apply();

参考阮一峰dalao的博客Javascript的this用法
还有《你不知道的JavaScript 上卷》

坚持原创技术分享,您的支持将鼓励我继续创作!

Mewhat Chen WeChat Pay

微信打赏

Mewhat Chen Alipay

支付宝打赏