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