JavaScript 中 this 和 bind 的使用

关于 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

转载于:https://my.oschina.net/agui1989/blog/3003313

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值