javascript实现计数器理解this作用域
2016-10-21 21:25
591 查看
众所周知,javascript的一大弊端便是全局作用域的使用。在想要计数的时候,定义一个全局变量计数显然是不可取的。利用面向对象编程的思想,我们想要实现一个计数器可能需要定义一个计数器类。但是想要利用javascript实现一个计数器,我们可以利用哪些方法呢?
首先,新手最先想到的可能是这样的:
但是,执行后是
原因在于每次函数执行时候都把cnt重新定义并且初始化成0了。那么会想,怎么只让它初始化一次呢?自然我们想到的就是让cnt的定义和初始化只执行一次。于是有:
到这里,计数器就可以使用了。但是为什么counter函数要返回this呢?
原因在于函数未显式指定返回值时候它默认会返回undefined。
更重要的问题是:此时this指向的是谁呢?是counter对象吗?我们接下去进行测试:
以上测试说明this指向的是global。为什么this不指向自身而指向counter呢?
这就涉及this作用域的问题,this的指向取决于函数调用的模式。接下来介绍常用的函数调用模式
上述helper的调用就是函数调用模式,由于helper内this指向的是全局对象,所以导致global.cnt值为9。此bug的改进可以将increaseTo函数改为如下形式
counter是一个计时器对象,increase是计时器的一个方法。increase方法可以通过this去访问对象,因为此时this指向的就是调用它的counter对象。
结合new前缀调用的函数被称为构造器函数。按照约定,他们以首字母大写命名。
通俗的讲,函数的功能就是把Function的代码放到obj内去执行,同时将args参数传递给Function。apply调用模式可以直接将Function函数的this指向obj。
首先,新手最先想到的可能是这样的:
function counter(){ var cnt=0; return ++cnt; }
但是,执行后是
counter();//结果是1 counter();//结果是1
原因在于每次函数执行时候都把cnt重新定义并且初始化成0了。那么会想,怎么只让它初始化一次呢?自然我们想到的就是让cnt的定义和初始化只执行一次。于是有:
function counter(){ var cnt=0; this.increase = function(){ cnt++; return cnt; } return this; } var myCounter= counter(); myCounter.increase();//结果是1 myCounter.increase();//结果是2
到这里,计数器就可以使用了。但是为什么counter函数要返回this呢?
原因在于函数未显式指定返回值时候它默认会返回undefined。
更重要的问题是:此时this指向的是谁呢?是counter对象吗?我们接下去进行测试:
console.log(global.increase);//结果是[Function]
以上测试说明this指向的是global。为什么this不指向自身而指向counter呢?
这就涉及this作用域的问题,this的指向取决于函数调用的模式。接下来介绍常用的函数调用模式
(1)函数调用模式
当一个函数并非一个对象的属性的时候,他直接以functionName()的方式被调用时候,它的this指向的是global全局对象。上述counter函数的调用就是这种模式。var counter = { cnt:0, increase:function(){ this.cnt ++; return this.cnt; }, increaseTo:function(i){ var helper = function(i){ this.cnt=i; } helper(i);//函数调用模式 return this.cnt; } } counter.increase();//结果是1 counter.increase();//结果是2 counter.increaseTo(9);//结果是2 console.log(global.cnt);//结果是9
上述helper的调用就是函数调用模式,由于helper内this指向的是全局对象,所以导致global.cnt值为9。此bug的改进可以将increaseTo函数改为如下形式
var counter = { cnt:0, increase:function(){ this.cnt++; return this.cnt; }, increaseTo:function(i){ var that = this; var helper = function(i){ that.cnt=i; } helper(i);//函数调用模式 return this.cnt; } } counter.increase();//结果是1 counter.increase();//结果是2 counter.increaseTo(9);//结果是9 console.log(global.cnt);//结果是undefined
(2)方法调用模式
在面向对象编程中,我们知道对象具有各种属性。当一个函数被保存为对象的一个属性的时候,我们称它为一个方法。当一个方法被对象调用的时候,this指向了这个对象。var counter = { cnt:0, increase:function(){ this.cnt++; return this.cnt; } } counter.increase();//结果为1(方法调用模式) counter.increase();//结果为2(方法调用模式)
counter是一个计时器对象,increase是计时器的一个方法。increase方法可以通过this去访问对象,因为此时this指向的就是调用它的counter对象。
(3)构造器调用模式
如果在一个函数前面带上new来调用,那么将创建一个包含该函数上下文的新对象。并且this将指向这个对象。function Counter(){ this.cnt=0; this.increase = function(){ this.cnt++; return this.cnt; } } var myCounter= new Counter();//构造器调用模式 myCounter.increase();//结果是1 myCounter.increase();//结果是2 console.log(global.cnt);//结果是undefined
结合new前缀调用的函数被称为构造器函数。按照约定,他们以首字母大写命名。
(4)apply调用模式
格式Function.apply(obj,args);通俗的讲,函数的功能就是把Function的代码放到obj内去执行,同时将args参数传递给Function。apply调用模式可以直接将Function函数的this指向obj。
function increase(cnt){ this.increase=function(){ cnt++; return cnt; } } function Counter(){ var cnt=0; increase.apply(this,[cnt]); } var myCounter= new Counter(); myCounter.increase();//结果是1 myCounter.increase();//结果是2
相关文章推荐
- JavaScript是否可实现多线程 —- 深入理解JavaScript定时机制
- JavaScript是否可实现多线程 深入理解JavaScript定时机制
- 理解call,this指针(用call实现继承),prototype模式实现继承的易错点
- JavaScript全面了解作用域(基础、this、闭包、继承)之二
- JavaScript全面了解作用域(基础、this、闭包、继承)之一
- javascript中的关键字this理解
- 深入理解JavaScript系列(13) This? Yes,this!
- JavaScript 开发进阶:理解 JavaScript 作用域和作用域链
- 理解Javascript_07_理解instanceof实现原理
- 深入理解JavaScript系列(13):This? Yes,this!
- Javascript 的词法作用域、调用对象和闭包--之深入理解(转)
- 理解Javascript_11_constructor实现原理
- 理解Javascript_07_理解instanceof实现原理
- JavaScript 开发进阶:理解 JavaScript 作用域和作用域链(上)
- vbscript实现javascript “this” 的功能
- 理解Javascript_11_constructor实现原理
- 理解Javascript_11_constructor实现原理
- 理解 JavaScript 的 this 关键字(代码)
- 深入理解JavaScript系列(13) This? Yes,this!