this在javascript中一直是新手难以理解的一部分。其实并不难,只要清楚几种调用模式,就容易掌握了。
函数调用模式
普通情况
var name = 'outer';
var fn = function() {
var name = 'inner';
console.log(this.name);
}
fn(); // outer
回调函数
无默认绑定
var name = 'outer';
var A = function() {
console.log(this.name);
};
var B = function(cb) {
var name = 'inner';
cb();
}
B(A); // outer
默认绑定
js中的事件机制,会默认绑定this
var name = 'outer';
var d = document.querySelector('div');
div.addEventListener('click', function(e) {
console.log(this.name); // undifined
}, false)
方法调用模式
var name = 'outer;
var obj = {
name: 'inner',
fn: function() {
console.log(this.name);
}
}
obj.fn() // inner
apply、call调用模式
var name = 'outer';
var obj = {
name: 'inner'
}
var fn = function() {
console.log(this.name);
}
fn() // outer;
fn.call(obj) // inner
fn.apply(obj) // inner
构造器调用模式
var name = 'outer';
var Fn = function(name) {
this.name = name;
}
Fn.prototype.print = function() {
console.log(this.name)
}
var obj = new Fn('inner');
obj.print() // inner
bind, call优先级
var name = 'outer';
var obj1 = {
name: 'inner1'
};
var obj2 = {
name: 'inner2';
};
var fn = function() {
console.log(this.name);
}
var f = fn.bind(obj1);
f(); // inner1
f.call(obj2) // inner1
可以看出,bind的优先级是比call要高的,当函数fn的this绑定为obj1后,再执行f.call(obj2),输出的name值还是name1,即this的值一直绑定为obj1。
es6的箭头函数
箭头函数的好处之一就是让我们省去了每次敲打function这个关键词,好处之二就是this值默认绑定为函数定义时的上下文,而跟调用模式无关。
var name = 'outer';
var obj = {
name: 'inner',
fn: ()=> {
console.log(this.name);
}
}
obj.fn() // outer
var name = 'outer';
var obj = {
name: 'inner'
};
var fn = ()=> {
console.log(this.name);
};
fn.call(obj) // outer
var name = 'outer';
var obj = {
name: 'inner'
};
var fn = ()=> {
console.log(this.name);
};
var f = fn.bind(obj);
f() // outer