JavaScript之this指向

2019-02-22  本文已影响0人  smaVivian

this 实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。

this绑定规则:

  1. 默认绑定,this指向全局对象window,严格模式下指向undefined
function foo() {
    console.log( this.a );
}
var a = 2;
foo(); // 2
  1. 隐式绑定,由上下文对象调用?绑定到那个上下文对象。
function foo() {
    console.log( this.a );
}
var obj = {
    a: 2,
    foo: foo
};
obj.foo(); // 2
  1. 显示绑定,由 call 或者 apply (或者 bind )调用?绑定到指定的对象。
function foo(str1, str2) {
    console.log( this.a );
}
var obj = {
    a:2
};
foo.call( obj, 'aa', 'aa2' ); // 2
  1. new绑定,绑定到新创建的对象
function foo(a) {
    this.a = a;
}
var bar = new foo(2);
console.log( bar.a ); // 2

优先级: new绑定 -> 显示绑定 -> 隐式绑定 -> 默认绑定

被忽略的 this

如果函数并不关心 this 的话,你仍然需要传入一个占位值,这时 null 可能是一个不错的选择

function foo(a,b) {
    console.log( "a:" + a + ", b:" + b );
}
// 把数组“展开”成参数
foo.apply( null, [2, 3] ); // a:2, b:3
// 使用 bind(..) 进行柯里化
var bar = foo.bind( null, 2 );
bar( 3 ); // a:2, b:3

然而,总是使用 null 来忽略 this 绑定可能产生一些副作用。如果某个函数确实使用了this (比如第三方库中的一个函数),那默认绑定规则会把 this 绑定到全局对象(在浏览器中这个对象是 window ),这将导致不可预计的后果

优化:
Object.create(null) 和 {} 很像,但是并不会创建 Object.prototype 这个委托,所以它比 {} “更空”

function foo(a,b) {
    console.log( "a:" + a + ", b:" + b );
}
// 我们的 DMZ 空对象
var _null = Object.create( null );
// 把数组展开成参数
foo.apply( _null, [2, 3] ); // a:2, b:3
// 使用 bind(..) 进行柯里化
var bar = foo.bind( _null, 2 );
bar( 3 ); // a:2, b:3

this词法:ES6中的箭头函数

ES6中的箭头函数,箭头函数不使用 this 的四种标准规则,而是根据当前的词法作用域来决定this ,具体来说,箭头函数会继承外层函数调用的 this 绑定(无论 this 绑定到什么)。这其实和 ES6 之前代码中的 self = this 机制一样。

我们来看看箭头函数的词法作用域:
function foo() {
    // 返回一个箭头函数
    return (a) => {
    //this 继承自 foo()
    console.log( this.a );
    };
}
var obj1 = {
    a:2
};
var obj2 = {
    a:3
};
var bar = foo.call( obj1 );   //  foo() 的 this 绑定到 obj1
bar.call( obj2 ); // 2, 不是 3 !  箭头函数的绑定无法被修改

foo() 内部创建的箭头函数会捕获调用时 foo() 的 this 。由于 foo() 的 this 绑定到 obj1 ,bar (引用箭头函数)的 this 也会绑定到 obj1 ,箭头函数的绑定无法被修改。( new 也不行!)

箭头函数最常用于回调函数中,例如事件处理器或者定时器:
function foo() {
    setTimeout(() => {
    // 这里的 this 在此法上继承自 foo()
    console.log( this.a );
    },100);
}
var obj = {
    a:2
};
foo.call( obj ); // 2
上一篇 下一篇

猜你喜欢

热点阅读