当前位置 博文首页 > 文章内容

    浅析Javascript 中的 this 的七种使用场景

    作者: 栏目:未分类 时间:2020-09-24 9:00:26

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    由于严格模式下,禁止this指向全局对象,所以以下示例均运行在非严格模式下

     

    情况一:全局 & 调用普通函数

    console.log(this === window);     //true

    普通函数在调用时候(注意不是构造函数,前面不加 new),其中的 this 也是指向 window。

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

     

    情况二:构造函数

    所谓的构造函数就是由一个函数 new 出来的对象,一般构造函数的函数名首字母大写,例如像 Object,Function,Array 这些都属于构造函数。

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

    上述代码,如果函数作为构造函数使用,那么其中的 this 就代表它即将 new 出来的对象。

    但是如果直接调用 Foo 函数,而不是 new Foo(),那就变成情况1,这时候 Foo() 就变成普通函数。

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

    情况三:对象方法

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

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

    注意:若是在对象方法中定义函数,那么情况就不同了。

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

    可以这么理解:函数 f 虽然是在 obj.foo 内部定义的,但它仍然属于一个普通函数,this 仍指向 window。

    在这里,如果想要调用上层作用域中的变量 obj.x,可以使用 self 缓存外部 this 变量。

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

    如果 foo 函数不作为对象方法被调用:

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

    情况四:构造函数 prototype 属性

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

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

    情况五:函数用 call、apply或者 bind 调用。

    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)();

    当一个函数被 call、apply 或者 bind 调用时,this 的值就取传入的对象的值。

    情况六:DOM event this

    function Listener(){   
        document.getElementById('foo').addEventListener('click', this.handleClick);     //这里的 this 指向 Listener 这个对象。不是强调的是这里的 this
    }
    Listener.prototype.handleClick = function (event) {
        console.log(this);    //<div id="foo"></div>
    }
    var listener = new Listener();
    document.getElementById('foo').click();

    这个很好理解,就相当于是给函数传参,使 handleClick 运行时上下文改变了,相当于下面这样的代码:

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

    你也可以用通过 bind 切换上下文:

    function  Listener(){
        document.getElementById('foo').addEventListener('click',this.handleClick.bind(this));      
    }
    Listener.prototype.handleClick = function (event) {
        console.log(this);    //Listener {}
    }
    var listener = new Listener();
    document.getElementById('foo').click();

    前六种情况其实可以总结为: this 指向调用该方法的对象。

    情况七:箭头函数中的 this

    当使用箭头函数的时候,情况就有所不同了:箭头函数内部的 this 是词法作用域,由上下文确定。

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

    现在,箭头函数完全修复了 this 的指向,this 总是指向词法作用域,也就是外层调用者 obj。

    如果使用箭头函数,以前的这种 hack 写法:

    var self = this;

    就不再需要了。

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

    由于 this 在箭头函数中已经按照词法作用域绑定了,所以,用 call()或者 apply()调用箭头函数时,无法对 this 进行绑定,即传入的第一个参数被忽略。