关于 this 指向的问题,经常看到讨论的文章,但我一直以为自己已经弄懂了,直到今天看到这样的代码:
function Router() {
console.log(this);
this.routes = {};
this.currentUrl = '';
}
Router.prototype.route = function(path, callback) {
console.log(this);
this.routes[path] = callback || function(){};
};
Router.prototype.refresh = function() {
console.log(this);
this.currentUrl = location.hash.slice(1) || '/';
this.routes[this.currentUrl]();
};
Router.prototype.init = function() {
window.addEventListener('load', this.refresh.bind(this), false);//这里的两个this让我很困惑
window.addEventListener('hashchange', this.refresh.bind(this), false);
}
window.Router = new Router();
window.Router.init();
// change Page anything
function changeBgColor(color) {
document.querySelector('body').style.backgroundColor = color;
}
Router.route('/', function() {
changeBgColor('white');
});
Router.route('/blue', function() {
changeBgColor('blue');
});
Router.route('/green', function() {
changeBgColor('green');
});
//来自:https://www.cnblogs.com/exhuasted/p/6839515.html
我觉得代码中的 bind(this) 好像没必要,于是删除了运行一下,发现就会报错。 于是我在每个函数中加了 console.log(this) ,更为神奇的是,我发现这些 this 竟然都指向 Router,而错误提示却显示找不到 Router.routes 。 这让我很困惑。
其实,这里我犯一个错误: console.log(this) 中的 this 并不一定是代码运行到那里的值,而是运行所有代码后计算的值,然后我在每个console.log(this) 后面一个个地加 debugger; 通过断点我确定了 refresh 函数内的 this 在没有 bind 的时候其实是指向 window 的。
于是,我测试了以下的代码:
var person={
age:12,
say(name){
console.log(this.age);
}
}
person.say();//12
var ss=person.say;
ss();//undefined,相当于 window.ss();
从测试的结果容易看到,直接通过 person.say()调用的时候,是 person 对象调用 say 方法,所以,say 内容的 this 指向 person; 当通过 ss()调用的时候,调用者是 window,所以,say 中的 this 这里指向的是window;
而 window.addEventListener("load",this.refresh),这里实际上是指导 Router 的 refresh 方法绑定到它的调用者 window 对象上,所以,refresh 内部的 this 其实是指向 window 的; 使用 window.addEventListener("load",this.refresh.bind(this)) 后则把 Router 的 refresh 方法中的 this 指向 Router 后再绑定到 window 中;所以,这里的两个 this 都是指向 Router 对象 (构造函数)。
上面的 ss 函数要正确调用的话,可以这样:
ss.bind(person,arg1,arg2)();//bind只是绑定,不调用,若要调用的话,要在后面加()
ss.call(person,arg1,arg2);//call 直接绑定且调用
ss.apply(person,[arg1,arg2]);//同 call,只是传传数的方法不一样。
更多相关知识,可以查看文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind