本文参考资料:《JavaScript设计模式与开放实践》、《ES6标准入门》
一、对象方法调用
当函数作为对象的方法调用时,它的this总是指向此对象
var name = 'hello world'
var obj = {
name: 'hello kitty',
getName: function(){
console.log(this.name)
}
}
obj.getName()
// 'hello kitty'二、普通函数调用
当函数不作为对象的方法调用时,就是普通函数调用。它的this总是指向全局对象,也就是window。
var name = 'hello world'
var obj = {
name: 'hello kitty',
getName: function(){
console.log(this.name)
}
}
var fn = obj.getName
fn()
// 'hello workld'三、构造函数调用
当new运算符调用构造函数时,该函数默认会返回一个对象,而this就指向返回的这个对象。
function Person(){
this.name = 'kitty'
}
var newPerson = new Person()
console.log(newPerson.name)
// 'kitty'
但是, 如果构造函数显示的返回一个对象,那么此次new运算会返回这个对象,而不是我们期待的this。
function Person(){
this.name = 'world'
return {
name: 'kitty'
}
}
var newPerson = new Person()
console.log(newPerson.name)
// 'kitty'此外,如果构造函数返回一个非对象类型的数据,会被自动忽略掉,this不变。
四、箭头函数调用
箭头函数本身没有this,它的this继承自定义时所在的对象,而不是使用时所在的对象。
this对象的指向随着调用方式的不同是可变的,但是在箭头函数中,它是固定的。
function Timer() {
this.s1 = 0;
this.s2 = 0;
// 箭头函数
setInterval(() => this.s1++, 1000);
// 普通函数
setInterval(function () {
this.s2++;
}, 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0
解析:
箭头函数,this指向构造函数Timer默认返回的对象{s1:0, s2: 0},1000毫秒加1,3100毫秒后执行了三次,timer.s1就是3。
普通函数,很明显是作为普通函数调用,它修改不了timer的值,所以timer.s2还是new Timer返回的默认对象没有变,timer.s2就是0。
如果非要刨根问底this.s2++干啥了,可以尝试一下下面的代码
this.a++ 或 window.a++五、call、apply改变指向
1. 它们都可以改变this指向,唯一不同的是参数传递方式不一样。
第一个参数用来指定函数体内this对象的指向。如果传入null,则等同于默认的宿主对象,浏览器环境是window。apply第二个参数为一个带下标的集合,可以是数组或类数组;call从第二个参数开始,数量不固定
function fn(a,b,c){
console.log(this)
console.log(a,b,c)
}
fn.apply(null, [1,2,3])
// window
// 1 2 3
fn.call({a:1,b:2},1,2,3)
// {a: 1, b: 2}
// 1 2 32. 方法借用。
构造函数B没有定义name属性,借用构造函数A实现。
function A(name){
this.name = name
}
function B(){
A.apply(this, arguments)
this.getName = function() {
console.log(this.name)
}
}
var b = new B('kitty')
b.getName() // 'kitty'