p.s 此文只说setTimeout。setInterval请如法炮制 。另,由于本人是新手,如有错误之处还望斧正。
setTimeout的第一个参数接受一个函数定义式。
function put(p1,p2){
console.log('put',p1,p2);
}
绑定函数和传入参数
setTimeout第一个参数传入一个函数定义式,第二个参数传入延迟时间。至于函数定义式参数的传入方式(准确说是给函数的参数们设置默认值。并返回这个带参数默认值的函数定义式。)
1.直接使用函数名,不带(),此时表示直接传入一个定义式。
setTimeout(put,1000);
缺点:不能给put定义式传参数
2.外部再包含一个function
setTimeout(function(){
put('some','value');
},1000)
缺点:可读性不高
优点:但最容易理解
3.使用bind传入参数
setTimeout(put.bind(this,p1,p2),1000);
bind的返回结果依然是一个函数定义式。但能传入指定的this,并传入指定的参数。
4.setTimeout余下参数
setTimeout(put,1000,p1,p2)
就很简单,在延迟参数后面继续跟参数就行了,全会被算到put函数上。不过低版本IE似乎不支持
this的问题
setTimeout默认的内部this就是window,你在一个别的对象里写个setTimeout直接用this会翻车。有如下修正方式
var someObj = {
name:'tmh',
intro:'一切为了老玩家',
getIntro:function(){
console.log(this.intro);
},
DelayPutIntro:function(){
setTimeout(/**一个this绑定指向正确的函数定义式**/,1000);
}
}
1.暴力指向,var self = this;
someObj.DelayPutIntro = function(){
var self = this; // setTimeout外部获取this,保存在self中
setTimeout(function(){
console.log(self.intro);
},1000)
}
someObj.DelayPutIntro();
2.bind绑定this
someObj.DelayPutIntro = function(){
setTimeout(someObj.getIntro.bind(this,p1,...,pn),1000);
}
someObj.DelayPutIntro();
上文提到过bind可以设置函数的参数默认值,同时也可以改变this指向。第一个参数用于控制this,后续参数用于绑定默认参数。
在程序尚未真正执行前,此处Bind中出现的this指代的是该function作用域内的this,即somObj。效果等同于setTimeout(someObj.getIntro.bind(someObj,p1,...,pn),1000)
注:由于bind第一个参数正确指向了this。所以也能写成这种形式setTimeout(this.getIntro.bind(this,p1,...,pn),1000);
3.()=>{}箭头函数
someObj.DelayPutIntro = function(){
setTimeout(
()=>{console.log(this.intro)},1000);
}
someObj.DelayPutIntro();
或者
someObj.DelayPutIntro = function(){
setTimeout(
()=>{this.getIntro()},1000);
}
someObj.DelayPutIntro();
箭头函数语法看ES6,除了表达更简便外,还能自动绑定this为定义时而不是使用时。范围同bind。
进一步,this的范围
this指向当前作用域的宿主。所以我们使用Bind或者箭头函数时,作用域是someObj.DelayPutIntro这个函数,其宿主为someObj。
为了证实this指向当前作用域的宿主
是可靠的。有如下例子:
var someObj = {
name: 'tmh',
intro: '一切为了老玩家',
getIntro: function () {
console.log(this.intro);
}
}
someObj.DelayPutIntro = function () {
var inner = {
name: '小tmh',
intro: '老玩家算个屁',
getIntro: function () {
console.log(this.intro);
},
DelayPutIntro: function () {
setTimeout(this.getIntro.bind(this), 1000);
}
}
inner.DelayPutIntro();
}
someObj.DelayPutIntro();
注意观察我们在someObj.DelayPutIntro函数中再创建了一个Inner对象。那么这段代码中setTimeout里函数定义式绑定的this应该指向什么?
是的,该this的作用域是inner.DelayPutIntro这个函数,故而this指向其宿主Inner,打印的结果也是inner的intro而不是someObj的intro了。
关于js对象,作用域,作用域链还有this指向的问题还有很多。此处不铺开阐述了。
总结一下
函数绑定及参数绑定
- 直接填写函数名传入不带参的定义式
- 外套一个function/或者()=>{}箭头函数,内部写一个传入了参的函数引用。
- xx.bind(this,...porps)返回一个xx改造后的新函数,该函数经由bind绑定了新的参数默认值
- setTimeout(put,1000,p1,p2,...,pn),直接在setTimeout的规定参数后面跟新参数,将绑到put上
this
- bind绑定
- 箭头函数绑定
- var self = this;暴力指向