Javascript之this指向

Posted by Shen Chaoran on June 28, 2018

函数中 this 的指向与函数定义无关,而与**调用方式**有关,常见的4中调用方式

  • 作为对象方法调用:指向对象
  • 作为函数直接调用:指向全局变量
  • 作为构造函数调用:指向构造的对象
  • 使用 apply, call, bind 调用:指向绑定的对象

作为对象方法调用

var obj = {
    a: 1,
    b: {
        a: 2,
        fn: function() {
            console.log(this.a)
        }
    }
}
obj.b.fn()
// a

直接调用

这里需要注意的一点是,直接调用并不是指在全局作用域下进行调用,在任何作用域下,直接通过 函数名(...) 来对函数进行调用的方式,都称为直接调用。

// 简单兼容浏览器和 NodeJs 的全局对象
const _global = typeof window === "undefined" ? global : window;

function test() {
    console.log(this === _global);    // true
}

test();    // 直接调用
(function(_global) {
    // 通过 IIFE 限定作用域

    function test() {
        console.log(this === _global);  // true
    }

    test();     // 非全局作用域下的直接调用
})(typeof window === "undefined" ? global : window);

apply, call, bind 对 this 的影响

function a(xx) {        
    this.b = xx;
}
var o = {};
a.apply(o, [5]);
a.call(o, 5);
alert(a.b);    // undefined
alert(o.b);    // 5

如果目标函数本身使用 bind 绑定了this对象,那么 apply 和 call 不会像预期那样执行:

const obj = {};

function test() {
    console.log(this === obj);
}

// 绑定到一个新对象,而不是 obj
const testObj = test.bind({});
test.apply(obj);    // true

// 期望 this 是 obj,即输出 true
// 但是因为 testObj 绑定了不是 obj 的对象,所以会输出 false
testObj.apply(obj); // false

如果apply的参数为空,默认调用全局对象

对比

| name| 立即调用 | 参数形式 | | —- | —- | —- | |apply| 是 | 数组 | |call| 是 | 不定参数 | | bind | 否 | 不定参数 |

方法调用

方法调用是指通过对象来调用其方法函数,它是 对象.方法函数(...) 这样的调用形式。这种情况下,函数中的 this 指向调用该方法的对象。但是,同样需要注意 bind() 的影响。

const obj = {
    // 第一种方式,定义对象的时候定义其方法
    test() {
        console.log(this === obj);
    }
};

// 第二种方式,对象定义好之后为其附加一个方法(函数表达式)
obj.test2 = function() {
    console.log(this === obj);
};

// 第三种方式和第二种方式原理相同
// 是对象定义好之后为其附加一个方法(函数定义)
function t() {
    console.log(this === obj);
}
obj.test3 = t;

// 这也是为对象附加一个方法函数
// 但是这个函数绑定了一个不是 obj 的其它对象
obj.test4 = (function() {
    console.log(this === obj);
}).bind({});

obj.test();     // true
obj.test2();    // true
obj.test3();    // true

// 受 bind() 影响,test4 中的 this 指向不是 obj
obj.test4();    // false

方法中 this 指向全局对象的情况

const obj = {
    test() {
        console.log(this === obj);
    }
};

const t = obj.test;
t();    // false
function foo() {
  console.log(this.a);
}
var obj = {
  a: 2,
  foo: foo
};
var a = "oops, global";
// 作为回调函数用时,实际上还是当做函数直接调用,而不是当做对象的方法调用
setTimeout(obj.foo, 100); // ?
obj.foo();

new 调用

箭头函数调用

bug

  • 在使用 jquery-ui 时,用了箭头函数,导致 this 指向出错。参考这里

参考