es5 this指向分四种情况
情况一:纯粹的函数调用
- 这是函数的最通常用法,属于全局性调用,因此this就代表全局对象。
var x = 1;
function test() {
console.log(this.x);
}
test(); // 1
情况二:作为对象方法的调用
- 函数还可以作为某个对象的方法调用,这时this就指这个上级对象。
function test() {
console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test;
// 类似这种写法
var obj = {
x:"1",
m: function() {
console.log(this.x);
}
}
console.log(obj.m())
obj.m(); // 1
情况三 作为构造函数调用
- 所谓构造函数,就是通过这个函数,可以生成一个新对象。这时,this就指这个新对象。
function test() {
this.x = 1;
}
var obj = new test();
obj.x // 1
- 运行结果为1。为了表明这时this不是全局对象,我们对代码做一些改变:
var x = 2;
function test() {
this.x = 1;
}
var obj = new test();
obj.x // 1
情况四 apply,call,bind 调用
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.apply(a),100);
}
};
a.func2() // Cherry
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout(function () {
this.func1()
}.call(a),100);
}
};
a.func2() // Cherry
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.bind(a)(),100);
}
};
a.func2() // Cherry
箭头函数和普通函数区别
* 没有 this,不能改变 this 绑定
* 不能通过 new 调用,当然也没有原型(prototype)
* 没有 arguments 对象,不能有相同命名参数
* 箭头函数虽然没有 this ,但是还是可以在内部使用 this 的
* this 的绑定取决于定义函数时的上下文环境
* 一旦函数调用,任何改变 this 的方法都无效
练习题
let x = 11111
let a = {
x: 1,
init() {
// 箭头函数的 this 取决于 init,所以可以打印出 1
document.addEventListener('click', () => console.log(this.x))
},
allowInit: () => {
// allowInit 直接是个箭头函数,所以这时的 this 变成了 window
// 但是并不会打印出 11111,使用 let 时变量也会被提升至块级作用域的顶部,但是只提升声明,不提升初始化
console.log(this.x)
},
otherInit() {
// 普通函数的 this 取决于调用函数的位置,this 指向 document
// 如果想打印出 x,可以使用 bind
document.addEventListener('click', function() {
console.log(this.x)
})
}
}
a.init() // -> 1
a.allowInit() // -> undefined
a.otherInit() // -> undefined