在执行上下文那篇文章中我们还留了一个Thisbinding没展开细节,全局的this指向没什么好说的,但是函数的this指向情况是有很多种的,但是this一定是指向一个对象的。
函数中的this指向取决于函数的调用方式,也就意味着this指向不是创建时确定的,不是静态的。是在调用时决定,是动态的。
函数调用
作为普通函数调用,包括立即执行函数。
- 在非strict mode下,普通函数调用中this为全局对象
- 在strict mode下,普通函数调用中this为undefined
方法调用
作为对象的方法调用时,this指向该对象。
var a = 2;
var someObj = {
a:1,
print:function(){
console.log(this.a)
}
}
var outPrint = someObj.print;
someObj.print(); // 1
outPrint();// 2
注意以下代码中,用实例化对象调用方法和原型直接调用方法的区别。
function Car(){
this.brand = 'Benz';
}
Car.prototype = {
brand: 'Mazda',
intro: function(){
console.log(this.brand);
}
}
var car = new Car();
car.intro(); // 'Benz'
Car.prototype.intro(); // 'Mazda'
构造函数调用
用new方式调用的函数运行上下文中,ThisBinding = newObject,因此在new方式调用的函数中,this指向新创建的对象,具体可以看原型链那篇文章。
间接调用
call()方法和apply()方法都可以指定this的值,区别在于apply采用数组形式传参。
以下代码将构造函数Car的this指向改成实例对象newCar。
function Car(brand, color){
this.brand = brand;
this.color = color;
}
var newCar = {};
Car.call(newCar, 'Benz', 'red');
console.log(newCar); // {brand: 'Benz', color: 'red'}
// 用伪代码可以表示为
// function Car(brand, color){
// newCar.brand = brand;
// newCar.color = color;
// }
以下代码是较为复杂的例子。
function Person(name, age){
this.name = name;
this.age = age;
}
function Programmer(name, age){
Person.apply(this, [name, age]);
this.work = '程序员';
}
var p = new Programmer('张三', 18);
console.log(p);
// Programmer {name: '张三', age: 18, work: '程序员'}
bind()调用
Function.prototype.bind()方法是创建一个和原函数一样的函数,但是它的this指向bind()函数的第一个参数。无论新函数如何被调用,this都会指向bind()的第一个参数。
function f() {
return this.a;
}
var g = f.bind({a: 'azerty'});
console.log(g()); // azerty
箭头函数调用
箭头函数是ES6的新内容,箭头函数的this是静态的,保存的是它被创建时所在的执行上下文的this。在global下创建箭头函数,它的this指向global对象。在function里创建,它的this指向function当前执行上下文的this的值。
这个和我们前面提到的函数都不一样,前面提到的函数都是和调用时的运行上下文相关,箭头函数的this却和创建时的运行上下文相关。
以下代码中可以看出定时器中的箭头函数的this指向,就是回调函数function的this指向,都是div。
let oBox1 = document.getElementsByClassName('box1')[0];
oBox1.onclick = function(){
console.log(this); // <div class="box1"></div>
setTimeout(() => {
console.log(this); // <div class="box1"></div>
this.style.background = 'pink';
},1000);
}
this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。
以下代码中当箭头函数作为事件回调函数时,它的this指向,就是init函数的this指向,即handler对象。
var handler = {
id: '123456',
init: function() {
document.addEventListener('click', event => {
console.log(this);
}, false);
}
};
handler.init(); // {id: '123456', init: ƒ}
注意对箭头函数使用call()、apply()和bind()来绑定this是无效,没有效果。
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
var obj = {func: foo};
console.log(obj.func() === globalObject); // true
console.log(foo.call(obj) === globalObject); // true
foo = foo.bind(obj);
console.log(foo() === globalObject); // true