修改setInterval作用域
Hello,今天和大家分享如何修改setInterval作用域。
0.引子
最近在做一个项目的时候需要开发一个图片轮播显示的组件,在实现过程中遇到了关于setInterval作用域的问题。
- SlidePicture.prototype={
- constructor:SlidePicture,
- init:function(){ //初始化函数
- this.autoPlay();
- },
- slidePic:function(){ //滑动图片具体实现
- //省略实现代码
- console.log('duration-->'+this.duration);
- console.log('delay-->'+this.delay);
- },
- autoPlay:function(){ //自动轮播图片
- setInterval(this.slidePic,this.delay);
- }
- }
- //构造函数
- function SlidePicture(delay,duration){
- this.delay=delay;
- this.duration=duration;
- this.init();
- }
- var sp=new SlidePicture(5000,800);
在上面的代码中,我们自定义并扩展一个SlidePicture原型。主要总用就是,我们在创建原型对象时会调用window的setInterval方法,
来定时调用图片切换方法,从而实现自动图片的自动轮播效果。
slidePic方法中具体的实现方法我先省略了(下次可以继续和大家分享这个完整的组件),只是在这里打印了对象中的两个属性值,
结果却出现以下信息:
都是undefined,为什么呢?
很明显问题不是出在SlidePicture对象上,因为我们已经给这个对象初始化过属性值了。
打开firebug脚本调试,在第8行打上断点:
终于发现了问题所在:slidePic方法中的this居然是指向window而不是当前的SlidePicture对象。
1.问题
我们重新审查代码,结果把关注点提到第12行来:
- setInterval(this.slidePic,this.delay);
问题来了,setInterval以及setTimeout这些方法都是全局作用域window的函数,
所以上面的代码等价于:
- setInterval(function(){
- console.log('duration-->'+this.duration);
- console.log('delay-->'+this.delay);
- },this.delay);
那么问题就清楚了,函数实现中的this当然是指向window了,千万别被this.slidePic蒙骗。
既然this就是window,那么delay,duration这两个属性当然也就不存在了。
2.apply/call?
既然是作用域的问题,那么解决问题的关键也就是如何修改setInterval的作用域了。
修改函数作用域,我们的第一个方案当然就是apply/call了,我们按照理论尝试将代码修改如下:
- autoPlay:function(){ //自动轮播图片
- var self=this;
- setInterval(self.slidePic.apply(self),this.delay);
- }
我们将当前对象this传递给apply方法,看起来应该是OK的,运行后结果如下:
果然,结果出来了。
等等,好像有点不对!这个结果只打印了一次,并不是根据setInterval定时循环调用的。
换成了call结果也一样。
查了查这两个方法:apply/call如果用在setInterval中的话,只会立即运行一次,而不会按照我们的设想循环调用。
怎么办?
我们的主角出场了:bind。
call和apply是立即执行方法,而bind是产生一个新方法用于后续调用。
我们修改了下代码:
- setInterval(self.slidePic.bind(self),this.delay);
果然我们想要的结果出现了:
3.匿名函数
还有没有别的办法?
其实在一开始的时候我们已经说了,给setInterval传递this.slidePic参数等价于:
- 1 setInterval(function(){
- 2 console.log('duration-->'+this.duration);
- 3 console.log('delay-->'+this.delay);
- 4 },this.delay);
这里我们定义了一个匿名函数作为参数setInterval的第一个参数,但是忽略了一点,
这个匿名函数中的this仍然指向window,所以这种做法当然也是不行。
那么我们只要将this换成我们的SlidePicture对象就可以了。
调整下代码:
- autoPlay:function(){ //自动轮播图片
- var self=this;
- // setInterval(self.slidePic.bind(self),this.delay);
- setInterval(function(){
- self.slidePic();
- },this.delay);
- }
在调用setInterval之前我们先将当前对象this保存下来,然后在匿名函数中调用了就OK了!
这也是处理this对象的一种常见方案。
------写得乱七八糟的,不管怎样希望对各位有所帮助-----
修改setInterval作用域的更多相关文章
- javascript 欺骗词法作用域
如果词法作用域完全由写代码期间函数所声明的位置来定义,怎样才能在运行时来"修改"(也可以说欺骗)词法作用域呢? JavaScript 中有两种机制来实现这个目的.社区普遍认为 ...
- JavaScript夯实基础系列(一):词法作用域
作用域是一组规则,规定了引擎如何通过标识符名称来查询一个变量.作用域模型有两种:词法作用域和动态作用域.词法作用域是在编写时就已经确定的:通过阅读包含变量定义的数行源码就能知道变量的作用域.Jav ...
- javasrcipt的作用域和闭包(二)
这篇博客主要对词法作用域与欺骗词法作用域.函数作用域与块级作用域.函数内部的变量提成原理进行详细的分析,在这篇博客之前,关于作用域.编译原理.浏览器引擎的原理及关系在javaScript的作用域和闭包 ...
- AngularJs之Scope作用域
前言: 上篇博文AngularJs之directive中说了Scope作用域是个大坑,所以拿出来作为重点总结! 什么是scope AngularJS 中,作用域是一个指向应用模型的对象,它是表达式的执 ...
- JavaScript:修改作用域外变量
今天在看JavaScript学习指南的时候做的课后习题,也因此详细的对函数的传入参数进行比较深入的研究. 题目如下: 函数如何才能修改其作用域之外的变量?编写一个函数,由1~5的数字组成的数组作为参数 ...
- JS中setInterval、setTimeout不能传递带参数的函数的解决方案
在JS中无论是setTimeout还是setInterval,在使用函数名作为调用句柄时都不能带参数,而在许多场合必须要带参数,接下来为大家介绍具体的解决方法 在JS中无论是setTimeout还是s ...
- 《你不知道的JavaScript》第一部分:作用域和闭包
第1章 作用域是什么 抛出问题:程序中的变量存储在哪里?程序需要时,如何找到它们? 设计 作用域 的目的:为了更好地存储和访问变量. 作用域:根据名称查找变量的一套规则,用于确定在何处以及如何查找变量 ...
- 理解AngularJS的作用域Scope
AngularJS中,子作用域一般都会通过JavaScript原型继承机制继承其父作用域的属性和方法.但有一个例外:在directive中使用scope: { ... },这种方式创建的作用域是一个独 ...
- phpcms后台部分修改
1.后台登陆前提示信息取消及成功后提示信息取消. (1)后台登陆前提示信息取消 phpcms\modules\admin\classes\admin.class.ph ...
随机推荐
- Android通过URL加载网络图片
public static Bitmap getBitmap(String path) throws IOException { URL url = new URL(path); HttpURLCon ...
- nginx(三)初步搭建nginx虚拟主机
上面就是nginx基于域名.ip访问的配置,掌握住格式,就很好配置了. 一.基于域名的虚拟主机的配置:1.我们在此复习一下DNS的配置:[root@mgmserver /]# hostnamemgms ...
- HTML快速入门4
七.表单 1. 概述 建立交互式的站点,需要使用 HTML 表单,它可以让用户提供信息,并对此作出处理.可以建立类似 复选框.单选按钮及文本框的控件. 掌握表单的使用对 Active Server P ...
- HDU 2955 Robberies 背包概率DP
A - Robberies Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submi ...
- Floyd算法 及其运用
#include<stdio.h> ][]; ][]; void floyd(int n) { ;k<=n;k++) { ;i<=n;i++) { ;j<=n;j++) ...
- django-cms 代码研究(三)插件(plugs in)
插件(plugs in) djangocms支持的插件有: http://docs.django-cms.org/en/latest/basic_reference/plugin_reference. ...
- iOS 中使用类别简化代码开发
最近需要一个函数,把CLLocation对象转化为NSDictionary,按照我以前的想法,我会写一个工具类,之后添加一个函数,类似这样 - (NSDictionary *)turnLocation ...
- Cocos2d-JS的屏幕适配方案
Cocos2d引擎为游戏开发者提供了屏幕适配策略(Resolution Policy)解决方案. 使用方式 1. 设置屏幕适配策略(Resolution Policy) 如果你还没有用过Resolut ...
- Android中如何让手机屏幕不待机
在Android中,申请WakeLock可以让你的进程持续执行即使手机进入睡眠模式,比较实用的是比如后台有网络功能,可以保证操作持续进行. 方法: 在操作之前加入 PowerManager pm = ...
- 关押罪犯(codevs 1069)
题目描述 Description S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极 不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨 ...