井井客

搜索

this指向问题

关于this指向的问题好像经久不衰,下面整理了一些我所理解的this场景和指向。

写在前面的话:非严格模式下,浏览器中如果this值为null或undefined,则会自动指向window(全局对象)。

1、全局

浏览器环境中,全局下this指向的是window。如:

    var a = 5;
    console.log(this.a);            // 5
    console.log(window.a);          // 5
    console.log(this === window);   // true

注意:let在全局定义的变量,并不放在window对象中,通过debugger可以发现它存在(Global)window平级的Script对象中(谷歌浏览器环境)。

2、函数和方法

不论是函数还是方法,this看准的都是它被调用的时候。

函数与方法调用标识就是那对括号,简单理解this指向的就是函数或方法名称前点的那个对象,而名称前无对象的话this则会指向window。

      // 例1
    var a = "window";
    var inside = {
        a: "inside",
        fn: function () {
            console.log(this.a);    // "inside"
        }
    };
    inside.fn();

上面的代码稍微变一下:

      // 例2
    var a = "window";
    var inside = {
        a: "inside",
        fn: function () {
            console.log(this.a);    // "window"
        }
    };
    var fn = inside.fn;
    fn();

这时,this就指向了window。还有一个有意思的例子:

    var a = "window";
    var inside = {
        a: "inside",
        fn: function () {
            console.log(this.a);
        }
    };

    setTimeout(inside.fn(), 100)    // inside
    setTimeout(inside.fn, 200)      //window

在100ms时候执行时更像例1,而在200ms执行时更像例2。而匿名函数中this指向window也能说通一些了吧。

3、call apply bind

下面看一段代码:

    var a = "window";
    var obj = {
        a: "obj"
    };
    var outside = {
        a: "outside",
        inside: function () {
            var a = "inside";
            console.log(this.a);    // outside
        }
    }
    outside.inside();

通过上面函数和方法中this的说明,可以知道,这时的this指向outside,而通过call/apply/bind我们可以指定this的值。

    var a = "window";
    var obj = {
        a: "obj"
    };
    var outside = {
        a: "outside",
        inside: function () {
            var a = "inside";
            console.log(this.a);
        }
    }
    outside.inside.call(obj);   // obj
    outside.inside.apply(obj);  // obj
    outside.inside.bind(obj)(); // obj
    // bind也可以先赋值,后再执行如:
    // var fn = outside.inside.bind(obj);
    // fn();
    // 而bind的特性让调用函数时,依然能够保持this指向obj

不考虑传参方式,明显的区别就是call与apply是立即执行,而bind可以稍后执行。

4、构造函数

我觉得构造函数里面的this最好理解,因为就是指向构造函数的实例对象。

    function Person(name) {
        this.name = name;
    }
    Person.prototype.sayName = function () {
        console.log("姓名是:" + this.name);
    }

    var person1 = new Person("张三");
    person1.sayName();  //姓名是:张三

    var person2 = new Person("李四");
    person2.sayName();  //姓名是:李四

5、箭头函数

箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。

作为方法调用时,使用剪头函数,关于this的疑惑,请看下面的代码:

    var a = "window";
    var outside = {
        a: "outside",
        inside: {
            a: "inside",
            fn: () => {
                console.log(this.a);    // window
            }
        }
    }
    outside.inside.fn();

正常因为调用方法时,this指向是调用方法的对象,即outside.inside。但是箭头函数需要向外层继承this,容易误会外层指向outside,但实际是函数才有作用域概念。

在浏览器中debugger会发现这时作用域this值是undefind,而实际打印的是window内的值。

进一步作为函数调用时,在上面这个代码上稍作修改:

    var a = "window";
    var outside = {
        a: "outside",
        inside: {
            a: "inside",
            fn: function () {
                console.log(this.a);        // inside
                (() => {
                    console.log(this.a);    // inside
                })()
            },
        }
    }
    outside.inside.fn();

fn里面的this指向inside应该没啥问题,而里面的自执行函数(包括setTimeout、setInterval),如果不用箭头函数,this指向window,使用后继承fn中的this。

而call apply bind中,也是一样的,通过继承this来确定值。

    var a = "window";

    var obj = {
        a: "obj"
    };

    var outside = {
        a: "outside",
        inside: {
            a: "inside",
            fn: function () {
                console.log(this.a);        // obj
                (() => {
                    console.log(this.a);    // obj
                })()
            },
        }
    }
    outside.inside.fn.call(obj);

如果fn也使用箭头函数,则它们最终都会打印window。因为箭头函数可以嵌套,所以导致this可能看上去就有点乱,如果不是特别熟悉复杂场景中建议慎用。

以上就是我关于this浅显的理解,如果有不正确的地方,欢迎拍砖,交流学习~

文章TAG:JS

作者:井井客整理来源:原创
本文标题:this指向问题
本文链接:/c/06332.html

上一篇:http-server命令行启动http服务器
下一篇:SVN版本控制软件cornerstone的简易教程

文章分类

相关阅读

随便看看