this机制是JavaScript非常重要的机制之一,了解this并运用它对一个JavaScript开发者很重要,让我们一起来领略一下this的魅力。
为什么要用this
首先我们先看一个例子:
function identify() {
return this.name.toUpperCase();
}
function speak () {
var greeting = "Hello, I'm " + identify.call( this );
}
var me = {
name: "Anna"
};
var you = {
name = "Bob"
};
identify.call( me ); // ANNA
identify.call( you ); // BOB
speak.call( me ); // Hello, I'm ANNA
speak.call( you ); // Hello, I'm BOB
这段代码可以在不同的上下文对象(me和you)中重复使用函数identify()和speak(),不用针对每个对象编写不同版本的函数。
this并不是按着英语的语法角度理解(指向自身),也不意味着指向函数的词法作用域。
如何判断一个运行中函数的this绑定
1.找到函数的直接调用位置
this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用,即函数的调用位置。调用位置就是函数在代码中被调用的位置,而不是声明位置。
2.四条规则来判断this的绑定对象
第一,默认绑定:无法应用其他规则时的默认规则。
第二,隐式绑定:当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。
最常见的this绑定问题就是被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定。
第三,显示绑定:使用函数的call(…)和apply(…)方法在某个对象上强制调用函数。
无法解决丢失绑定的问题,但是可以通过显式绑定的变种(硬绑定)解决。
bind(…)函数会返回一个硬编码的新函数,它会把你指定的参数设置为this的上下文并调用原始函数。
第四,使用new操作符被调用的函数即构造函数,使用new来调用函数时,会构造一个新对象并把它绑定到函数调用的this上。
这些规则的优先级是按下面的顺序来执行的:
- 由new调用?绑定到新创建的对象。
- 由call或者apply(或者bind)调用?绑定到指定的对象。
- 由上下文对象调用?绑定到那个上下文对象。
- 默认:在严格模式下绑定到undefined,否则绑定到全局对象。
3.ES6中的箭头函数
箭头函数并不会使用四条标准的绑定规则,而是根据当前的词法作用域来决定this。箭头函数的绑定无法被修改,会继承外层函数调用的this绑定。
function foo () {
// 返回一个箭头函数
return (a) => {
//this继承自foo()
console.log( this.a );
};
}
var obj1 = {
a: 2
};
var obj2 = {
a: 3
};
var bar = foo.call( obj1 );
bar.call( obj2 ); // 2,不是3!