this指向

this永远指向最后调用它的对象

例1:

    var name = "windowsName";
    function a() {
        var name = "name";

        console.log(this.name);          // windowsName

        console.log("inner:" + this);    // inner: Window
    }
    a();
    console.log("outer:" + this)         // outer: Window

a调用的地方在a(),前面没有调用的对象,即为window.a(),所以window指向window

例2:

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

fn()由对象a调用,所以fn()中的this指向对象a。

window.a.fn()中,最后调用this的对象仍然是a,所以依旧输出name

例3:

    var name = "windowsName";
    var a = {
        name : null,
        // name: "name",
        fn : function () {
            console.log(this.name);      // windowsName
        }
    }

    var f = a.fn;
    f();

a对象没有调用fn,只是赋值给了f,真正调用fn的是f(),也就是仍然是window调用

例4:

    var name = "windowsName";

    function fn() {
        var name = 'name';
        innerFunction();
        function innerFunction() {
            console.log(this.name);      // windowsName
        }
    }

    fn()

补充知识:innerFunction()是作为一个函数调用,不属于某一个对象,仅仅是一个函数,没有挂载在任何对象上,所以innerFunction()内的this在非严格模式默认是指向全局对象 window 的,在严格模式,就是 undefined。

改变this指向

方法:

  • ES6 的箭头函数
  • 在函数内部使用 _this = this
  • 使用 applycallbind
  • new 实例化一个对象

例1:

    var name = "windowsName";

    var a = {
        name : "name",

        func1: function () {
            console.log(this.name)     
        },

        func2: function () {
            setTimeout(  function () {
                this.func1()
            },100);
        }

    };

    a.func2()     // this.func1 is not a function

补充知识:function () {this.func1()}是一个匿名函数,因为匿名函数没有办法被其他对象调用,所以匿名函数的 this 永远指向 window。PS:匿名函数只能通过自执行或被其他函数调用,比如例子中的setTimeout

setTimeout 的对象是 window,但是在 window 中并没有 func1 函数,所以会报错

箭头函数

“箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined”

箭头函数的 this 始终指向函数定义时的 this,而非执行时

    var name = "windowsName";

    var a = {
        name : "name",

        func1: function () {
            console.log(this.name)     
        },

        func2: function () {
            setTimeout( () => {
                this.func1()
            },100);
        }

    };

    a.func2()     // name        

在函数内部使用 _this = this

将函数的对象保存在变量_this中,用_this代替this来调用,指向就不会改变了

    var name = "windowsName";

    var a = {

        name : "name",

        func1: function () {
            console.log(this.name)     
        },

        func2: function () {
            var _this = this;
            setTimeout( function() {
                _this.func1()
            },100);
        }

    };

    a.func2()       // name

使用 apply、call、bind

apply

    var a = {
        name : "name",

        func1: function () {
            console.log(this.name)
        },

        func2: function () {
            setTimeout(  function () {
                this.func1()
            }.apply(a),100);
        }

    };

    a.func2()            // name

apply() 方法调用一个函数, 其具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数

语法:

fun.apply(thisArg, [argsArray])

  • thisArg:在 fun 函数运行时指定的 this 值。需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。
  • argsArray:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。

call

    var a ={
        name : "name",
        fn : function (a,b) {
            console.log( a + b)
        }
    }

    var b = a.fn;
    b.apply(a,[1,2])     // 3
    var a ={
        name : "name",
        fn : function (a,b) {
            console.log( a + b)
        }
    }

    var b = a.fn;
    b.call(a,1,2)       // 3

apply 和 call 基本类似,他们的区别只是传入的参数不同。call 方法接受的是若干个参数列表,而 apply 接收的是一个包含多个参数的数组。

语法:

fun.call(thisArg, arg1, arg2, ...)

bind

    var a = {
        name : "name",

        func1: function () {
            console.log(this.name)
        },

        func2: function () {
            setTimeout(  function () {
                this.func1()
            }.bind(a)(),100);
        }

    };

    a.func2()            // name

bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值。个函数的 this 指向除了使用 new 时会被改变,其他情况下都不会改变。

可以看出,bind 是创建一个新的函数,必须要手动去调用:

    var a ={
        name : "name",
        fn : function (a,b) {
            console.log( a + b)
        }
    }

    var b = a.fn;
    b.bind(a,1,2)()           // 3

注意:

  • 在this的指向中,使用构造器调用模式(new)的优先级最高,然后是 apply、call 和 bind 调用模式,然后是方法调用模式(obj.fun()),然后是函数调用模式(fun()指向全局变量)。